2017-08-13 81 views
1

協議我有一個協議:夫特聲明equatable

protocol CustomProtocol { 
    var title: String { get } 
    var subtitle: String { get } 
} 

然後我有2個目的,符合這個網絡協議。我想比較他們,所以我想CustomProtocol是Equatable。

protocol CustomProtocol: Equatable { 
    var title: String { get } 
    var subtitle: String { get } 
    static func ==(lhs: Self, rhs: Self) -> Bool 
} 

extension CustomProtocol { 
    static func ==(lhs: Self, rhs: Self) -> Bool { 
     return lhs.title == rhs.title 
    } 
} 

但是這種改變,我得到「協議CustomProtocol只能作爲一種通用的約束,因爲它具有自我或相關類型requeriments後 我能想到的解決,這是有一個第三個屬性一樣的唯一途徑依賴於他人,比較該物業的哈希值。

enter image description here

Here you have a sample操場上用實際的代碼。

+0

您需要從更新的協議聲明中刪除相等函數,因爲它們只在擴展中需要。 – Ollie

+0

比較https://stackoverflow.com/q/41298464/2976878 – Hamish

回答

1

的Equatable protoc ol有一個自我約束來解決這個問題,你應該只能檢查相同類型的對象之間的相等性,而不是相同的協議。這就是爲什麼它有自我要求。否則,你可以說

let a: Equatable = 42 
let b: Equatable = "hello" 

a == b會工作。這會很糟糕,因爲你可以比較完全不相關類型的對象。自我需求使得這是一個編譯時錯誤。

如果你想你的對象的協議的基礎上比較,只需實現==操作者沒有自我要求:

extension CustomProtocol { 
    func == (lhs: CustomProtocol, rhs: CustomProtocol) -> Bool { 
     return lhs.name == rhs.name 
    } 
    func != (lhs: CustomProtocol, rhs: CustomProtocol) -> Bool { 
     return !(lhs == rhs) 
    } 
} 

現在你可以用CustomProtocol型直接宣告你的協議的情況下,並加以比較。

但是在這種情況下協議可能不是正確的抽象。也許你應該把它作爲一個抽象類來實現。

+0

我得到'不明確的參考==' – Godfather

+0

當然你的協議不能再從'Equatable'繼承。 – Palle

+0

我添加了一個示例Playground,刪除繼承後也是一樣。 – Godfather

0

因爲EquatableSelf的要求,所以不應該直接在協議上實現。否則,該協議將作爲一種類型不可用。

要在協議級別實現Equatable,但能夠使用該協議作爲類型,則可以使用類型擦除。

爲了演示,我修改了您的操場中給出的代碼來構建橡皮擦。

因爲我使用的方法的詳細說明,請參閱這個職位上我的博客:

https://khawerkhaliq.com/blog/swift-protocols-equatable-part-two/

這裏是你的遊樂場修改後的代碼:

protocol CustomProtocol { 
    var title: String { get } 
    var subtitle: String { get } 
    func isEqualTo(_ other: CustomProtocol) -> Bool 
    func asEquatable() -> AnyEquatableCustomProtocol 
} 

extension CustomProtocol where Self: Equatable { 
    func isEqualTo(_ other: CustomProtocol) -> Bool { 
     guard let o = other as? Self else { return false } 
     return self == o 
    } 
    func asEquatable() -> AnyEquatableCustomProtocol { 
     return AnyEquatableCustomProtocol(self) 
    } 
} 

struct A: CustomProtocol, Equatable { 
    var title: String 
    var subtitle: String 
    static func ==(lhs: A, rhs: A) -> Bool { 
     return lhs.title == rhs.title && lhs.subtitle == rhs.subtitle 
    } 
} 

struct B: CustomProtocol, Equatable { 
    var title: String 
    var subtitle: String 
    static func ==(lhs: B, rhs: B) -> Bool { 
     return lhs.title == rhs.title && lhs.subtitle == rhs.subtitle 
    } 
} 

struct AnyEquatableCustomProtocol: CustomProtocol, Equatable { 
    var title: String { return value.title } 
    var subtitle: String { return value.subtitle } 
    init(_ value: CustomProtocol) { self.value = value } 
    private let value: CustomProtocol 
    static func ==(lhs: AnyEquatableCustomProtocol, rhs: AnyEquatableCustomProtocol) -> Bool { 
     return lhs.value.isEqualTo(rhs.value) 
    } 
} 

// instances typed as the protocol 
let a: CustomProtocol = A(title: "First title", subtitle: "First subtitle") 
let b: CustomProtocol = B(title: "First title", subtitle: "First subtitle") 
let equalA: CustomProtocol = A(title: "First title", subtitle: "First subtitle") 
let unequalA: CustomProtocol = A(title: "Second title", subtitle: "Second subtitle") 

// equality tests 
print(a.asEquatable() == b.asEquatable())   // prints false 
print(a.asEquatable() == equalA.asEquatable())  // prints true 
print(a.asEquatable() == unequalA.asEquatable()) // prints false 

點需要注意的是,通過這種方法,實際的==比較被委託給底層的具體類型,但我們只處理協議類型以維護抽象。

在這裏,我只使用了擦除類型的實例來進行一次比較。但是,由於類型橡皮擦符合CustomProtocol,因此可以在任何需要協議類型的地方保存和使用這些實例。因爲它們符合Equatable,所以它們也可以用於任何需要符合要求的地方。

只是爲了背景下,這篇文章解釋了爲什麼這是不可取的嘗試直接在協議執行Equatable一致性,甚至==功能:

https://khawerkhaliq.com/blog/swift-protocols-equatable-part-one/

因此,類型擦除。

希望這會有所幫助。