Swift 协议扩展中的“关联类型”难以理解
Posted
技术标签:
【中文标题】Swift 协议扩展中的“关联类型”难以理解【英文标题】:Difficulty understanding `Associated Types` in Swift protocol extensions 【发布时间】:2015-10-11 00:43:48 【问题描述】:我很难快速理解协议和协议扩展。
我想定义一系列可应用于类的协议,以及一组协议扩展以提供默认实现。示例代码:
// 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'
。如果我从Self.ResultType
中删除Self
,则会收到错误'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
如果我完全不了解协议扩展如何提供默认实现,我对如何实现相同结果持开放态度。
【问题讨论】:
【参考方案1】: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"
我们可以在StringOutputItem
中显式声明ResultType
,这将确保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'
【讨论】:
以上是关于Swift 协议扩展中的“关联类型”难以理解的主要内容,如果未能解决你的问题,请参考以下文章