'self' 在所有存储属性初始化之前使用
'self' used before all stored properties are initialized
我正在研究 learn-swift playground 并在学习语言时将其升级到 Swift 2.0。以下代码(可能适用于 Swift 的早期版本)现在会生成两个错误:“'self' 在所有存储的属性初始化之前使用”和 "Constant 'self.capitalCity' used before initialized"
class Country
{
let name: String
let capitalCity: City!
init(name: String, capitalName: String)
{
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}
class City
{
let name: String
unowned let country: Country
init(name: String, country: Country)
{
self.name = name
self.country = country
}
}
读取 answer to a similar question 我看到我可以将 let capitalCity: City!
更改为 var capitalCity: City!
并且语法错误已解决。
我意识到在这个人为的例子中,一个国家的首都可以改变,所以这很好,但如果有一个值真的是常量的情况......
有什么方法可以在保持 capitalCity 不变的情况下解决语法错误吗?
Is there any way to resolve the syntax error while keeping capitalCity
a constant?
不是你设置的方式。问题的根源其实是为了设置capitalCity
,你必须创建一个country
为self
的City。 那个是编译器反对的self
的使用:
self.capitalCity = City(name: capitalName, country: self)
^^^^
由于您已将 City 的 country
配置为常量,因此您 必须 在初始化 City 时提供此值。这样你就没有出路了;您必须使 capitalCity
成为可选的 var
,以便它具有一些 other 合法的初始值,即 nil
。您提出的解决方案实际上是这样工作的:
class Country
{
let name: String
var capitalCity: City! = nil // implicit or explicit
init(name: String, capitalName: String)
{
self.name = name
// end of initialization!
// name is set (to name), and capitalCity is set (to nil)...
// ... and so the compiler is satisfied;
// now, we _change_ capitalCity from nil to an actual City,
// and in doing that, we _are_ allowed to mention `self`
self.capitalCity = City(name: capitalName, country: self)
}
}
在这种情况下,我建议您使 属性 成为一个变量,但通过计算 属性:
隐藏它(让它看起来像一个常量)
class Country {
let name: String
private var _capitalCity: City!
var capitalCity: City {
return _capitalCity
}
init(name: String, capitalName: String) {
self.name = name
self._capitalCity = City(name: capitalName, country: self)
}
}
就这样:
private(set) var capitalCity: City!
它为您提供所需的只读 public 界面。
我知道您觉得 var capitalCity: City!
做作。我会说 确实是做作的;它添加的代码行除了解决与语言相关的问题外没有其他目的。这样的行是没有意义的,意义是代码中最重要的地方。
最近在遇到类似问题时遇到了这个问题,从 swift 5.5(或可能更低)开始,还有另一个有趣的选择。如果您将 Capital City 转换为 lazy var
,您实际上可以在初始化中使用 self。
class Country
{
let name: String
lazy var capitalCity: City = {
City(name: capitalName, country: self)
}()
private let capitalName: String
init(name: String, capitalName: String)
{
self.name = name
self.capitalName = capitalName
}
}
class City
{
let name: String
unowned let country: Country
init(name: String, country: Country)
{
self.name = name
self.country = country
}
}
干杯!
我正在研究 learn-swift playground 并在学习语言时将其升级到 Swift 2.0。以下代码(可能适用于 Swift 的早期版本)现在会生成两个错误:“'self' 在所有存储的属性初始化之前使用”和 "Constant 'self.capitalCity' used before initialized"
class Country
{
let name: String
let capitalCity: City!
init(name: String, capitalName: String)
{
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}
class City
{
let name: String
unowned let country: Country
init(name: String, country: Country)
{
self.name = name
self.country = country
}
}
读取 answer to a similar question 我看到我可以将 let capitalCity: City!
更改为 var capitalCity: City!
并且语法错误已解决。
我意识到在这个人为的例子中,一个国家的首都可以改变,所以这很好,但如果有一个值真的是常量的情况......
有什么方法可以在保持 capitalCity 不变的情况下解决语法错误吗?
Is there any way to resolve the syntax error while keeping
capitalCity
a constant?
不是你设置的方式。问题的根源其实是为了设置capitalCity
,你必须创建一个country
为self
的City。 那个是编译器反对的self
的使用:
self.capitalCity = City(name: capitalName, country: self)
^^^^
由于您已将 City 的 country
配置为常量,因此您 必须 在初始化 City 时提供此值。这样你就没有出路了;您必须使 capitalCity
成为可选的 var
,以便它具有一些 other 合法的初始值,即 nil
。您提出的解决方案实际上是这样工作的:
class Country
{
let name: String
var capitalCity: City! = nil // implicit or explicit
init(name: String, capitalName: String)
{
self.name = name
// end of initialization!
// name is set (to name), and capitalCity is set (to nil)...
// ... and so the compiler is satisfied;
// now, we _change_ capitalCity from nil to an actual City,
// and in doing that, we _are_ allowed to mention `self`
self.capitalCity = City(name: capitalName, country: self)
}
}
在这种情况下,我建议您使 属性 成为一个变量,但通过计算 属性:
隐藏它(让它看起来像一个常量)class Country {
let name: String
private var _capitalCity: City!
var capitalCity: City {
return _capitalCity
}
init(name: String, capitalName: String) {
self.name = name
self._capitalCity = City(name: capitalName, country: self)
}
}
就这样:
private(set) var capitalCity: City!
它为您提供所需的只读 public 界面。
我知道您觉得 var capitalCity: City!
做作。我会说
最近在遇到类似问题时遇到了这个问题,从 swift 5.5(或可能更低)开始,还有另一个有趣的选择。如果您将 Capital City 转换为 lazy var
,您实际上可以在初始化中使用 self。
class Country
{
let name: String
lazy var capitalCity: City = {
City(name: capitalName, country: self)
}()
private let capitalName: String
init(name: String, capitalName: String)
{
self.name = name
self.capitalName = capitalName
}
}
class City
{
let name: String
unowned let country: Country
init(name: String, country: Country)
{
self.name = name
self.country = country
}
}
干杯!