我看了"Protocol-Oriented Programming in 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",
// i.e. 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 T.x
}
}
// And finally the property is successfully overridden (but why?).
print(Test<Z>().test()) // "zzz\n"
这是否真的意味着当类中使用的协议时,来自协议的static
关键字(以及可能的默认实现)可以合法地用class
关键字替换?你知道有什么参考证实吗?
答案 0 :(得分:5)
从Language Reference / Declarations我们知道以下内容。
功能声明
...
特殊方法
...
与类型相关联的方法而不是类型实例必须使用
static
声明修饰符标记枚举和结构或class
声明修饰符对于课程。
即。 static
关键字(主要)用于枚举和结构,class
关键字用于类。
还有这样一个说明:
类型变量属性
...
注意
在类声明中,关键字
static
与使用class
和final
声明修饰符标记声明具有相同的效果。
即。实际上 的static
关键字可以在类声明中使用,并且意味着final class
。
协议方法声明
...
要在协议声明中声明类或静态方法要求,请使用
static
声明修饰符标记方法声明。实现此方法的类使用class
修饰符声明该方法。实现它的结构必须使用static
声明修饰符来声明该方法。如果您要在扩展程序中实施该方法,请在扩展类时使用class
修饰符,如果要扩展结构,请使用static
修饰符。
这里的文档声明我们应该在类或类扩展中实现协议时用static
关键字替换协议声明中的class
关键字(这是对原始文件的准确答案)问题)。
有两种情况,协议采用仅限于类。第一个(也是最不明确的)是协议包含optional
成员:
协议声明
...
默认情况下,符合协议的类型必须实现协议中声明的所有属性,方法和下标。也就是说,您可以使用
optional
声明修饰符标记这些协议成员声明,以指定它们的符合类型的实现是可选的。optional
修饰符只能应用于标有objc
属性的协议。 因此,只有类类型可以采用并符合包含可选成员要求的协议。 ...
第二个(明确的;下一个段落):
要仅限制将协议用于类类型,请将
class
关键字作为继承协议中的第一项标记为具有class
要求的协议冒号后的列表。 ...
但考虑到static
和class
关键字的适用性,它们都没有改变规则。