[英]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.