快速协议扩展默认实现与类中的实际实现

时间:2019-06-17 14:57:15

标签: swift swift-protocols

考虑以下代码:

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),在本例中为“名称”,是从类中使用的,而不是默认的“名称”通过协议扩展实现?

2 个答案:

答案 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"
    }
}

所以答案是,在这种情况下,没有任何“保证”;这完全取决于对象的键入方式。协议扩展可能会破坏动态调度。