class Test { let hello = "hello" let world = "world" let phrase: String { return self.hello + self.world } }
解决方法
You must declare computed properties — including read-only computed@H_404_25@ properties — as variable properties with the var keyword,because their@H_404_25@ value is not fixed. The let keyword is only used for constant@H_404_25@ properties,to indicate that their values cannot be changed once they@H_404_25@ are set as part of instance initialization.
因此,您需要使用var来反映计算属性值随时可能发生变化的事实,因为您在访问它时会动态创建它.虽然在你的代码中,这不可能发生 – 因为你的hello和world属性是自己的常量.但是,Swift无法推断出这一点,所以你仍然需要使用var.
例如:
class Test { let hello = "hello" let world = "world" var phrase: String { return self.hello + self.world } }
(这不会改变属性的可读性 – 因为你没有为它提供setter,它仍然是只读的)
但是在您的情况下,您可能需要考虑使用lazy property,因为您的hello和world属性是常量.惰性属性在首次访问时创建,并在其生命周期的剩余时间内保持其值 – 这意味着每次访问它时都不必继续将两个常量连接在一起.
例如:
class Test { let hello = "hello" let world = "world" lazy var phrase: String = { return self.hello + self.world }() }
let属性的另一个特征是它们的值应该在初始化之前始终是已知的.因为在此之前可能不知道惰性属性的值,所以还需要将其定义为var.
如果你仍然坚持想要一个let属性,那么据我所知,你有两个选择.
第一个是最好的(尽管你已经说过你不想这样做) – 你可以在初始化器中分配你的短语属性.只要你在super.init调用之前执行此操作,就不必处理选项.例如:
class Test { let hello = "hello" let world = "world" let phrase: String init() { phrase = hello+world } }
你根本无法内联,因为该范围的self指的是静态类,而不是类的实例.因此,您无法访问实例成员,并且必须使用init()或惰性/计算属性.
第二个选项很糟糕 – 您可以在类级别镜像您的hello和world属性,因此您可以在短语声明中内联访问它们.例如:
class Test { static let hello = "hello" static let world = "world" // for some reason,Swift has trouble inferring the type // of the static mirrored versions of these properties let hello:String = Test.hello let world:String = Test.world let phrase = hello+world }