在初始化所有存储属性之前使用'self'

时间:2015-12-26 19:33:59

标签: swift initialization swift2

我正在学习learn-swift playground并在学习语言时将其升级到Swift 2.0。下面的代码(可能与之前版本的Swift一起使用)现在产生两个错误:“在初始化所有存储属性之前使用'self'”和在初始化之前使用“Constant'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不变?

3 个答案:

答案 0 :(得分:16)

在这种情况下,我建议你通过计算属性使属性成为变量但隐藏它(使它看起来像一个常量):

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

答案 1 :(得分:12)

  

有什么方法可以解决语法错误,同时保持capitalCity不变?

不是你设置的方式。问题的根源实际上是,为了设置capitalCity,您必须创建countryself的城市。 是编译器反对的self的使用:

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

由于您已将城市的country配置为常量,因此在初始化城市时,必须提供此值。因此你没有出路;您必须使capitalCity成为可选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)
    }
}

答案 2 :(得分:0)

只需:

private(set) var capitalCity: City!

为您提供所需的只读公共接口。

我了解到您发现var capitalCity: City!人为。我会说the selected answer确实是人为的;它添加了除了解决与语言有关的问题外没有其他用途的代码行。这样的行是毫无意义的,而意义是代码中内容最重要的部分。