Kol*_*lja 6 protocols associated-types swift
我有一个协议我的swift代码库我有协议与相关的类型和两个方法.这两种方法都为协议的相关类型定义了不同的通用约束.我想使结构符合协议,但有两种不同的关联类型.
protocol Convertable {
associatedtype TargetType
func convert() -> TargetType
}
func show<T : Convertable where T.TargetType == String>(toShow : T) {
print(toShow.convert())
}
func add<T : Convertable where T.TargetType == Int>(a : T, b : T) -> Int {
return a.convert() + b.convert()
}
struct MyData {
var data : Int
}
Run Code Online (Sandbox Code Playgroud)
作为扩展我使该结构符合的协议,其中TargetType将String以便将它传递给显示方法:
extension MyData : Convertable {
func convert() -> String { return String(self.data) }
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切都按预期工作.但是现在我也希望Convertable在TargetType绑定到Int 时使结构符合协议.哪个似乎不可能?
我尝试的第一件事是将convert方法的第二个定义添加到扩展名:
extension MyData : Convertable {
func convert() -> String { return String(self.data) }
func convert() -> Int { return data }
}
Run Code Online (Sandbox Code Playgroud)
编译器现在抱怨MyData不再符合协议.其次是将其拆分为两个扩展并显式绑定TargetType.
extension MyData : Convertable {
typealias TargetType = Int
func convert() -> Int { return data }
}
extension MyData : Convertable {
typealias TargetType = String
func convert() -> String { return String(data) }
}
Run Code Online (Sandbox Code Playgroud)
这会产生编译器现在抱怨TargetType重新定义的效果.
我的最后一次尝试是定义两个扩展Convertable协议并约束的协议TargetType,然后通过扩展实现它们:
protocol ConvertableString : Convertable {
associatedtype TargetType = String
}
protocol ConvertableInt : Convertable {
associatedtype TargetType = Int
}
extension MyData : ConvertableInt {
func convert() -> Int { return self.data }
}
extension MyData : ConvertableString {
func convert() -> String { return String(self.data) }
}
Run Code Online (Sandbox Code Playgroud)
现在这使得编译器对扩展感到满意,但不再适用于调用,show因为它不知道它可以调用函数MyData.
是否有一些事情我已经监督过或者目前在swift中是不可能的?
我只是资助一种归档方式。诀窍是在协议的子类型之一中添加另一个关联类型:
protocol ConvertableInt : Convertable {
associatedtype TResI
typealias TargetType = TResI
}
extension MyData : Convertable {
typealias TargetType = String
func convert() -> String { return String(self.data) }
}
extension MyData : ConvertableInt {
typealias TResI = Int
func convert() -> TResI { return self.data }
}
Run Code Online (Sandbox Code Playgroud)
这也允许摆脱字符串的第二个子类型。
虽然这通过了编译器,但它在运行时完全崩溃了!
编译器总是调用在显式定义的方法typealias。在这种情况下:
typealias TargetType = String
Run Code Online (Sandbox Code Playgroud)
这将导致将地址解释为整数并给出完全错误的结果。如果你反之亦然地定义它,它就会崩溃,因为它试图将整数解释为地址。