[英]Difficulty understanding `Associated Types` in Swift protocol extensions
我正在努力快速地了解協議和協議擴展。
我想定義一系列可應用於類的協議,以及一組協議擴展以提供默認的實現。 示例代碼:
// MARK: - Protocols & Protocol Extensions
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
// other requirements ...
}
protocol StringOutputItem : OutputItem {}
extension StringOutputItem {
typealias ResultType = String
override func rawValue() -> Self.ResultType {
return "string ouput"
}
}
protocol IntOutputItem: OutputItem {}
extension IntOutputItem {
typealias ResultType = Int
override func rawValue() -> Self.ResultType {
return 123
}
}
擴展中rawValue()
的上述重寫函數Ambiguous type name 'ResultType' in 'Self'
給出了錯誤的Ambiguous type name 'ResultType' in 'Self'
。 如果我從Self.ResultType
刪除Self
, 'ResultType' is ambiguous for type lookup in this context
,我將得到錯誤'ResultType' is ambiguous for type lookup in this context
。
我如何向協議擴展發出信號,以將哪種類型用於ResultType
?
我的目標是能夠將協議及其擴展應用於以下類:
// MARK: - Base Class
class DataItem {
// Some base class methods
func randomMethod() -> String {
return "some random base class method"
}
}
// MARK: - Subclasses
class StringItem : DataItem, StringOutputItem {
// Some subclass methods
}
class AnotherStringItem : DataItem, StringOutputItem {
// Some subclass methods
}
class IntItem : DataItem, IntOutputItem {
// Some subclass methods
}
以便:
let item1 = StringItem()
print(item1.rawValue()) // should give "string output"
let item2 = AnotherStringItem()
print(item2.rawValue()) // should give "string output"
let item3 = IntItem()
print(item3.rawValue()) // should give 123
如果我對協議擴展如何提供默認實現完全不滿意,那么我對如何實現相同結果持開放態度。
Swift編譯器通過已實現的協議方法的類型簽名來推斷ResultType
的類型。 例如,在以下StringOutputItem
聲明中,編譯器知道StringOutputItem
的ResultType
的類型為String
,即使沒有顯式聲明也是如此:
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
func rawValue() -> String {
return "string output"
}
}
class StringItem : DataItem, StringOutputItem {}
let item = StringItem()
print(item.rawValue()) // prints "string output"
我們可以在ResultType
中顯式聲明StringOutputItem
,這將僅確保StringOutputItem
符合OutputItem
協議並以正確的類型實現它。
為了說明關聯類型的類型推斷,假設OutputItem
指定另一種方法作為其協議的一部分。 如果我們提供默認的實現,其中類型不匹配,則編譯器將拋出錯誤,指示實現的類型不符合協議。
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
func printValue(r: ResultType)
}
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
func rawValue() -> String {
return "string output"
}
func printValue(r: Int) { // Should be String
...
}
}
struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
通過在StringOutputItem
顯式聲明typealias ResultType = String
,我們可以確保在實現協議的方法時使用正確的類型。
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
func printValue(r: ResultType)
}
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
typealias ResultType = String // without this typealias declaration, the program WILL compile since ResultType is inferred to be of type Int
func rawValue() -> Int {
return 123
}
func printValue(r: Int) {
...
}
}
struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.