Swift:协议扩展中的静态属性可以被覆盖,但是为什么呢? [英] Swift: static property in protocol extension CAN be overridden, but why?

查看:243
本文介绍了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",
// 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"

这实际上是否意味着当在类中使用协议时,可以使用class关键字合法地替换协议(以及可能的默认实现)中的static关键字?您是否知道任何参考资料可以证实这一点?

解决方案

来自"Protocol-Oriented Programming in Swift" and read the related docs, but I still think there is a conflict in the following sample code (try it in a 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"

Does this actually mean that static keyword from protocol (and possible default implementation) can be legitimately replaced with class keyword when the protocol used in classes? Do you know any references confirming that?

解决方案

From Language Reference / Declarations we know the following.

Function Declaration

...

Special Kinds of Methods

...

Methods associated with a type rather than an instance of a type must be marked with the static declaration modifier for enumerations and structures or the class declaration modifier for classes.

I.e. the static keyword is (mainly) for enumerations and structures and the class keyword is for classes.

There is also such a note:

Type Variable Properties

...

NOTE

In a class declaration, the keyword static has the same effect as marking the declaration with both the class and final declaration modifiers.

I.e. the static keyword actually can be used in class declaration and will mean final class.

So what about protocols?

Protocol Method Declaration

...

To declare a class or static method requirement in a protocol declaration, mark the method declaration with the static declaration modifier. Classes that implement this method declare the method with the class modifier. Structures that implement it must declare the method with the static declaration modifier instead. If you’re implementing the method in an extension, use the class modifier if you’re extending a class and the static modifier if you’re extending a structure.

Here the docs state that we should replace the static keyword from protocol declaration with the class keyword when implementing the protocol in a class or a class extension (and this is the exact answer to the original question).

Bonus

There are two cases in which protocol adoption will be restricted to classes only. The first (and the least explicit) is when a protocol includes optional members:

Protocol Declaration

...

By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional declaration modifier to specify that their implementation by a conforming type is optional. The optional modifier can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. ...

And the second (explicit; the next paragraph):

To restrict the adoption of a protocol to class types only, mark the protocol with the class requirement by writing the class keyword as the first item in the inherited protocols list after the colon. ...

But neither of them changes the rules considering the static and the class keywords applicability.

这篇关于Swift:协议扩展中的静态属性可以被覆盖,但是为什么呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆