Swift:协议扩展中的静态属性可以被覆盖,但为什么?
我看了“Swift中的面向协议的编程”并阅读了相关的文档,但是我仍然认为在下面的示例代码中存在冲突(在Playground中尝试)。
protocol X { // The important part is "static" keyword static var x: String { get } } extension X { // Here "static" again static var x: String { get { return "xxx" } } } // Now I'm going to use the protocol in a class, BUT // in classes "static" is like "final class", // ie CAN'T BE OVERRIDDEN, right? // But I'd prefer to have the ability to override that property, // so I'll try to use "class" keyword. // Will it break the program? (spoiler: no!) class Y: X { // Here we are allowed to use "class" keyword (but why?). class var x: String { get { return "yyy" } } } class Z: Y { override class var x: String { get { return "zzz" } } } class Test<T: X> { func test() -> String { return Tx } } // And finally the property is successfully overridden (but why?). print(Test<Z>().test()) // "zzz\n"
这实际上是否意味着协议中的static
关键字(和可能的默认实现)可以合法地用class
关键字replaceclass
使用的协议? 你知道任何参考证实吗?
从语言参考/声明我们知道以下。
函数声明
…
特殊的方法
…
与types相关联的方法而不是types的实例必须用枚举和结构的
static
声明修饰符或class
声明修饰符来标记。
即static
关键字是(主要)为枚举和结构和class
关键字是类。
也有这样一个说明:
typesvariables属性
…
注意
在类声明中,关键字
static
与使用class
和final
声明修饰符标记声明具有相同的效果。
即static
关键字实际上可以在类声明中使用,将意味着final class
。
那么协议呢?
协议方法声明
…
要在协议声明中声明类或静态方法要求,请使用
static
声明修饰符标记方法声明。 实现此方法的class
使用class
修饰符声明方法。 实现它的结构必须用static
声明修饰符来声明方法。 如果要在扩展中实现该方法,请在扩展class
使用class
修饰符,如果扩展了结构,请使用static
修饰符。
这里的文档声明,当在类或类扩展中实现协议时(这是对原始问题的确切答案),我们应该使用class
关键字从协议声明中replacestatic
关键字。
奖金
有两种情况下协议的采用将仅限于类。 第一个(也是最不明确的)是当协议包含optional
成员时:
议定书声明
…
默认情况下,符合协议的types必须实现在协议中声明的所有属性,方法和下标。 也就是说,可以使用
optional
声明修饰符标记这些协议成员声明,以指定通过一致性types的实现是可选的。optional
修饰符只能应用于使用objc
属性标记的协议。 因此,只有types可以采用并符合包含可选成员要求的协议 。 …
第二个(明确的;下一段):
要将协议限制为类types,可以通过将
class
关键字作为inheritance协议列表中的第一项写入冒号后面来标记具有class
要求的协议 。 …
但是考虑到static
和class
关键字的适用性,它们都不会改变规则。