Swift 中 struct init 的编译器错误
Compiler errors for struct init in Swift
我有以下结构:
struct Person {
let name: String
let age: Int
let assets: Double
}
为了初始化一个人,我想给它传递一个包含姓名和年龄的字典,以及计算资产的信息:
public init(info: [String : AnyObject]) {
if let name = info["name"] as? String {
self.name = name
}
if let age = info["age"] as? Int {
self.age = age
}
if let assets = info["assets"] as? [String : AnyObject] {
calculateAssets(assets: assets)
}
}
mutating func calculateAssets(assets: [String : AnyObject]) {
self.assets = 1+2+3.4 // really do this with info from the dictionary
}
使用此设置,出现两个编译器错误:
- 'self' 在所有存储属性初始化之前使用
- Return 来自初始化器而不初始化所有存储的属性
按照编译器的建议,我为每个 属性 添加了一个默认值,并将它们更改为 var
:
struct Person {
var name: String = ""
var age: Int = 0
var assets: Double = 0.0
// init ...
}
事实上,编译器错误已经消失。
但是我进行这些更正是否在正确的轨道上?
你得到了编译器错误,因为当你设置它们时你的变量是not inited
。(你将它们定义为inited
)。这就是为什么在第二种情况下,当您 init
将它们设置为 nil
值时,error
消失了。对于这种情况,Swift 有 optionals
。可以同时为 nil 和一个值。检查 here。您可以添加 ?
并使变量 optional
.
struct Person {
var name: String?
var age: Int?
var assets: Double?
// init ...
}
问题是,在您的 init
函数中,您 可能 初始化变量,但您不能确定,因为 if
语句可以是 false
。这就是编译器给你错误的原因(也是因为你试图在另一个函数中调用 self.assets
而变量可能仍未初始化 - 所以你至少需要将这个更改为 var
).
如果您不能确定 info
字典中的值是否有效,您应该将变量更改为 var
。
现在你有两个选择:
- 给你的变量一个默认值(就像你在你的例子中所做的那样)
- 将您的变量声明为
Optionals
(如@Özgür 所建议)。
您的选择取决于什么更有意义。如果您的默认值对您的情况有意义,并且您可以使用具有这些值的变量,那么我会接受它。
否则,你应该选择Optionals
。 Optionals
显然有一个优点,那就是你不需要初始化它们,但缺点是你需要在以后使用它们时隐式或显式地解包它们(使用 ?
或 !
).
如果 - 出于任何原因 - 你可以确定 info
字典中的值是有效的 - 你也可以离开你的 name
和age
作为常量 (let
) 并在分配字典值时显式展开字典值:
self.name = info["name"] as! String
self.age = info["age"] as! Int
但正如我所说,这只有在 info["name"]
和 info["age"]
包含有效值时才有效,否则您将遇到运行时异常。所以 "default value" 或 "Optional" 选项是安全和干净的选择,而这是快速和肮脏的方式。
我有以下结构:
struct Person {
let name: String
let age: Int
let assets: Double
}
为了初始化一个人,我想给它传递一个包含姓名和年龄的字典,以及计算资产的信息:
public init(info: [String : AnyObject]) {
if let name = info["name"] as? String {
self.name = name
}
if let age = info["age"] as? Int {
self.age = age
}
if let assets = info["assets"] as? [String : AnyObject] {
calculateAssets(assets: assets)
}
}
mutating func calculateAssets(assets: [String : AnyObject]) {
self.assets = 1+2+3.4 // really do this with info from the dictionary
}
使用此设置,出现两个编译器错误:
- 'self' 在所有存储属性初始化之前使用
- Return 来自初始化器而不初始化所有存储的属性
按照编译器的建议,我为每个 属性 添加了一个默认值,并将它们更改为 var
:
struct Person {
var name: String = ""
var age: Int = 0
var assets: Double = 0.0
// init ...
}
事实上,编译器错误已经消失。
但是我进行这些更正是否在正确的轨道上?
你得到了编译器错误,因为当你设置它们时你的变量是not inited
。(你将它们定义为inited
)。这就是为什么在第二种情况下,当您 init
将它们设置为 nil
值时,error
消失了。对于这种情况,Swift 有 optionals
。可以同时为 nil 和一个值。检查 here。您可以添加 ?
并使变量 optional
.
struct Person {
var name: String?
var age: Int?
var assets: Double?
// init ...
}
问题是,在您的 init
函数中,您 可能 初始化变量,但您不能确定,因为 if
语句可以是 false
。这就是编译器给你错误的原因(也是因为你试图在另一个函数中调用 self.assets
而变量可能仍未初始化 - 所以你至少需要将这个更改为 var
).
如果您不能确定 info
字典中的值是否有效,您应该将变量更改为 var
。
现在你有两个选择:
- 给你的变量一个默认值(就像你在你的例子中所做的那样)
- 将您的变量声明为
Optionals
(如@Özgür 所建议)。
您的选择取决于什么更有意义。如果您的默认值对您的情况有意义,并且您可以使用具有这些值的变量,那么我会接受它。
否则,你应该选择Optionals
。 Optionals
显然有一个优点,那就是你不需要初始化它们,但缺点是你需要在以后使用它们时隐式或显式地解包它们(使用 ?
或 !
).
如果 - 出于任何原因 - 你可以确定 info
字典中的值是有效的 - 你也可以离开你的 name
和age
作为常量 (let
) 并在分配字典值时显式展开字典值:
self.name = info["name"] as! String
self.age = info["age"] as! Int
但正如我所说,这只有在 info["name"]
和 info["age"]
包含有效值时才有效,否则您将遇到运行时异常。所以 "default value" 或 "Optional" 选项是安全和干净的选择,而这是快速和肮脏的方式。