2016-04-24 38 views
6

我有一个协议我的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 
} 

作为扩展我使结构符合该协议在TargetTypeString,以便将其传递给显示方法:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
} 

到目前为止一切正常。但是现在我还希望在TargetType绑定到Int时使结构符合Convertable协议。这似乎是不可能的?

我想的第一件事就是到转换方法的第二个定义添加到扩展:

extension MyData : Convertable { 
    func convert() -> String { return String(self.data) } 
    func convert() -> Int { return data } 
} 

编译器现在抱怨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) } 
} 

这有编译器现在抱怨的了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) } 
} 

使得现在的编译器快乐的扩展,但不再对show的呼叫,因为它不知道它可以用MyData调用该功能。

有没有我监督过的一些事情,或者这是目前不可能在迅速?

+1

在我看来,这不仅是不可能的,而且几乎是不可能的。你已经用_one single_关联类型声明了一个协议。如何将它设置为同一类型的两种不同类型? – werediver

+1

这不是同一个协议,因为协议在TargetType上是通用的,所以协议的变体与TargetType一样多。与协议类型相关的整个想法是,您可以通过它们的关联类型进行区分。如果你看看C#,那么可以实现绑定到泛型参数的不同类型的相同接口。 – Kolja

+0

嗯,这不是C#,你不应该这样想,因为那不起作用。 – werediver

回答

1

我只是资助一种方法来存档这个。诀窍是在协议的其中一个子类型中添加另一个关联类型:

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 } 
} 

这也允许摆脱字符串的第二个子类型。

虽然这通过编译器它在运行时完全崩溃!

编译器总是调用在显式typealias处定义的方法。在这种情况下:

typealias TargetType = String 

这将导致将地址解释为整数并给出完全错误的结果。如果你反过来定义它,它会简单地崩溃,因为它试图将整数解释为一个地址。

相关问题