swift2 在初始化所有存储属性之前使用了“self”

fcipmucu  于 2022-11-23  发布在  Swift
关注(0)|答案(4)|浏览(329)

我在学习Swift的同时,正在学习一个learn-swift游戏场,并将其升级到Swift 2.0。下面的代码(可能在Swift的早期版本中也能运行)现在生成了两个错误:“在初始化所有存储属性之前使用了'self'”和“在初始化之前使用了常量'self.capitalCity'”

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为常量的同时解决语法错误?

wvt8vs2t

wvt8vs2t1#

在这种情况下,我建议您将该属性设置为变量,但通过计算属性将其隐藏(使其看起来像常量):

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)
    }
}
fruv7luv

fruv7luv2#

有没有办法在保持capitalCity不变的情况下解决语法错误?
问题的根源实际上是为了设置capitalCity,你必须创建一个City,它的countryself。* 这 * 就是编译器所反对的self的用法:

self.capitalCity = City(name: capitalName, country: self)
                                                    ^^^^

由于您已经将City的country配置为常量,因此在初始化City时必须提供该值。您必须将capitalCity设置为Optional var,以便它具有合法的 * 其他 * 初始值,即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)
    }
}
3z6pesqy

3z6pesqy3#

只是做:

private(set) var capitalCity: City!

这将为您提供所需的只读公共接口。
我知道您发现var capitalCity: City!是人为的。它会添加一些代码行,这些代码行除了解决与语言相关的问题之外没有其他用途。像这样的代码行是没有意义的,而"意义"才是代码中最重要的。

3okqufwl

3okqufwl4#

最近遇到了一个类似的问题,在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
    }
}

干杯!干杯!

相关问题