Swift:协议扩展中的静态属性可以被覆盖,但为什么呢?

时间:2015-11-12 14:35:41

标签: ios swift swift2

我看了"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关键字替换?你知道有什么参考证实吗?

1 个答案:

答案 0 :(得分:5)

Language Reference / Declarations我们知道以下内容。

  

功能声明

     

...

     

特殊方法

     

...

     

与类型相关联的方法而不是类型实例必须使用static声明修饰符标记枚举和结构class声明修饰符对于课程

即。 static关键字(主要)用于枚举和结构,class关键字用于类。

还有这样一个说明:

  

类型变量属性

     

...

     

注意

     

在类声明中,关键字static与使用classfinal声明修饰符标记声明具有相同的效果。

即。实际上 static关键字可以在类声明中使用,并且意味着final class

那么协议呢?

  

协议方法声明

     

...

     

要在协议声明中声明类或静态方法要求,请使用static声明修饰符标记方法声明。实现此方法的类使用class修饰符声明该方法。实现它的结构必须使用static声明修饰符来声明该方法。如果您要在扩展程序中实施该方法,请在扩展类时使用class修饰符,如果要扩展结构,请使用static修饰符。

这里的文档声明我们应该在类或类扩展中实现协议时用static关键字替换协议声明中的class关键字(这是对原始文件的准确答案)问题)。

加成

有两种情况,协议采用仅限于类。第一个(也是最不明确的)是协议包含optional成员:

  

协议声明

     

...

     

默认情况下,符合协议的类型必须实现协议中声明的所有属性,方法和下标。也就是说,您可以使用optional声明修饰符标记这些协议成员声明,​​以指定它们的符合类型的实现是可选的。 optional修饰符只能应用于标有objc属性的协议。 因此,只有类类型可以采用并符合包含可选成员要求的协议。 ...

第二个(明确的;下一个段落):

  

要仅限制将协议用于类类型,请将class关键字作为继承协议中的第一项标记为具有class要求的协议冒号后的列表。 ...

但考虑到staticclass关键字的适用性,它们都没有改变规则。