问题
I watched "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?
回答1:
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 theclass
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 theclass
andfinal
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 theclass
modifier. Structures that implement it must declare the method with thestatic
declaration modifier instead. If you’re implementing the method in an extension, use theclass
modifier if you’re extending a class and thestatic
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. Theoptional
modifier can be applied only to protocols that are marked with theobjc
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 theclass
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.
来源:https://stackoverflow.com/questions/33673900/swift-static-property-in-protocol-extension-can-be-overridden-but-why