考虑以下代码:
protocol MyProtocol {
static var name: String { get }
}
extension MyProtocol {
static var name: String {
return "unnamed"
}
}
// does not specify its own name
class MyClass: MyProtocol {
}
//specifies its own name!
class MyClass2: MyProtocol {
static var name: String {
return "Specific name"
}
}
let myClass = MyClass()
print("\(MyClass.name)")
//>>"unnamed"
let myClass2 = MyClass2()
print("\(MyClass2.name)")
//>>"Specific name"
迅速保证对于具有协议属性的实际实现的类(例如在本例中为MyClass2),在本例中为“名称”,是从类中使用的,而不是默认的“名称”通过协议扩展实现?
答案 0 :(得分:1)
拥有必需协议功能/属性的默认实现意味着您的符合类型将不必实现该功能/属性,而是可以使用默认实现。
但是,如果符合类型确实实现了功能/属性,则编译器将始终调用更具体的实现,即符合类中的实现,而不是默认的实现。
因此,即使将MyClass2
的实例存储在类型为MyProtocol
的变量中,在访问变量的属性时,仍然可以获得MyClass2
的实现。
let myClass2: MyProtocol = MyClass2()
type(of: myClass2).name // "Specific name"
对于协议扩展中声明和定义的非必需属性/功能,其行为是不同的。如果仅在协议扩展中声明属性/功能,则即使在一致性类中为该扩展提供了不同的实现,也无法从类型为协议类型而不是协议类型的变量访问该实现。特定的符合类型。
protocol MyProtocol {
static var name: String { get }
}
extension MyProtocol {
static var name: String {
return "unnamed"
}
// Optional protocol requirement
static var nonRequired: String {
return "nonRequired"
}
}
// does not specify its own name
class MyClass: MyProtocol { }
//specifies its own name!
class MyClass2: MyProtocol {
static var name: String {
return "Specific name"
}
// Specific implementation
static var nonRequired: String {
return "Specific"
}
}
let myClass = MyClass()
MyClass.name
let myClass2: MyProtocol = MyClass2()
type(of: myClass2).name // "Specific name"
type(of: myClass2).nonRequired // "nonRequired"
MyClass2.nonRequired // "Specific"
答案 1 :(得分:0)
不幸的是,您的示例错过了真正有趣的用例。使您的属性成为实例属性,而不是静态属性,然后从协议中删除gem install bundler
要求:
bundle install
现在:
name
好的,请注意:
protocol MyProtocol {
}
extension MyProtocol {
var name: String {
return "unnamed"
}
}
class MyClass: MyProtocol {
}
class MyClass2: MyProtocol {
var name: String {
return "Specific name"
}
}
所以答案是,在这种情况下,没有任何“保证”;这完全取决于对象的键入方式。协议扩展可能会破坏动态调度。