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
}

作为扩展,我使结构符合TargetType将要使用的协议,String以便将其传递给 show 方法:

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

到目前为止,一切都按预期工作。但是现在我也希望结构体在绑定到 IntConvertable时符合协议。TargetType这似乎是不可能的?

我尝试的第一件事是将 convert 方法的第二个定义添加到扩展中:

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

这具有编译器现在抱怨 theTargetType被重新定义的效果。

我最后一次尝试是定义两个扩展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.

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

4

1 回答 1

0

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

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

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

于 2017-01-10T00:30:10.043 回答