假设我有一个类A和B,如下所示:
class A {
var x: Int { return 9 }
func p() { print(x) }
}
class B: A {
...
}
let v: A = B()
v.p()
然后我以三种不同的方式覆盖B中的x:
class B: A {
// OPTION 1: FINE - prints 10
override var x: Int { return 10 }
// OPTION 2: ERROR - cannot override with a stored property 'x'
override var x = 10
// OPTION 3: FINE - prints 10
override lazy var x = 10
}
有人可以解释一下使用存储属性覆盖计算属性的错误,为什么当我声明它是懒惰时突然修复了所有内容?
答案 0 :(得分:2)
没有真正的技术原因导致您无法使用存储属性覆盖属性;它有getter和setter(访问器),它可以覆盖要覆盖的属性的访问器。它应该等同于覆盖计算属性,然后转发到存储的属性。
但是,我确实预见到允许这样一个轻微的复杂性:属性观察者覆盖。
考虑以下示例:
class C {
var f: Int {
get { return 5 }
set { print("C says f was set") }
}
}
class D : C {
override var f: Int {
didSet {
print("D says f was set")
}
}
}
let d = D()
print(d.f)
d.f = 7
print(d.f)
// 5
// C says f was set
// D says f was set
// 5
我们可以在f
中覆盖didSet
' D
。在这种情况下,override var f: Int
基本上被视为具有getter和setter的计算属性,该getter和setter转发到super
,并且另外调用setter中的didSet
实现。
此处D
未引入实际的存储空间。那么为什么这会有问题呢?那么,我们如何告诉编译器我们做实际上想要f
的存储?添加初始化表达式(= 10
)可以传达该表达式,但并非所有存储的属性都具有默认值;大多数都是从班级初始化的。指定的初始化者。我们可能需要某种属性,但对于这种有限的用例,它似乎不是对语言特别有用的改变。
lazy
案例很明确,因为我们无法向他们添加属性观察者。
尽管如此,你提出的具体案例也是明确的;因为基本属性只有一个getter,所以没有属性观察者可以覆盖。我建议你file a bug(希望)看看Swift团队对此有何看法。
您始终可以使用计算属性覆盖获得相同的结果,然后通过以下方式转发到存储的属性:
class C {
var f: Int {
return 9
}
}
class D : C {
private var _f: Int = 10
override var f: Int {
get { return _f }
set { _f = newValue }
}
}
let d = D()
print(d.f) // 10
d.f = 7
print(d.f) // 7