带有关联类型和影子类型擦除的Swift协议

时间:2019-04-01 07:25:44

标签: swift protocols swift-protocols associated-types

我需要将一个实现带有相关类型的协议的对象传递给一个接受协议的方法。这在Swift(最新的Swift 5)中是不可能的,因此我将类型擦除与基于this blog的影子协议结合使用。

protocol ShadowA {
    func test(data: Any) -> String
}

extension ShadowA {
    func test(data: Any) -> String {
        return "shadow"
    }
}

protocol A: ShadowA {
    associatedtype AT

    func test(data: AT) -> String
}

class SpecificA: A {
    typealias AT = Int

    func test(data: Int) -> String {
        return "specific"
    }
}

问题是,当我将对象传递给方法时,将调用“影子的默认实现”,而不是“通用”实现。您可以检查playground看看发生了什么。

是不是有什么问题,或者在Swift中根本不可能使用这种用例?

1 个答案:

答案 0 :(得分:0)

此动态分派和直接分派Magic对此检查swift-method-dispatch

进行了详细说明
  

动态调度是选择一个实施的过程   在运行时调用的多态操作(方法或函数)。

protocol extension中实现的任何方法都是直接调度的

我会解释更多

因为ShadowAprotocol并具有default implementation扩展名,所以编译器的想法是“ Any class can adopt to this protocol without implement this method because it have default implementation

直接发送

因此,在这一行中,编译器从item那里了解test(data:Any),并且因为item是具有默认实现的协议,所以它将其定向为直接默认实现

return "in method: \(item.test(data: 0))"

func passedIntoMethod(item: ShadowA) -> String {
    return "in method: \(item.test(data: 0))"
}

也在这一行

let a2: ShadowA = SpecificA()   // becuse compiler know only about a2 at this line that it is Protocol so it direct dispatch it  
print(a2.test(data: 0))

动态调度

在这里,编译器知道a1是concreate类型,因此它调用在其内部实现的test Method。如果未实现,则会调用默认实现

let a1 = SpecificA()
print(a1.test(data: 0))