Swift - 继承协议类型擦除

时间:2018-03-04 05:31:12

标签: swift swift-protocols

我有3个协议和一个必须确定最专业协议的功能

protocol Super {}
protocol Sub1: Super { associatedtype T }
protocol Sub2: Super {}

func test(_ s: Super) { ... do stuff }

现在我尝试了类型擦除

class AnySub<E>: Sub1 {
    typealias T = E
    // ... standard type erasure init
}

进行以下更改:

protocol Super {
    func tryAsSub1() -> AnySub? {}
}
extension Sub1 { 
    func tryAsSub1() -> AnySub<T> { return AnySub<T>() }
}
extension Sub2 {
    func tryAsSub1() -> AnySub { return nil }
}
func test(_ s: Super) {
    if let sub1 = s.tryAsSub1() { ... do stuff for Sub1 }
    else let sub2 = s as? Sub2 { ... do stuff for Sub2 }
}

但这显然不起作用,因为我在Super和Sub2中没有任何通用参数。 有没有人有想法,我怎么解决这个问题?

1 个答案:

答案 0 :(得分:0)

由于Sub1使用关联类型,因此无法在运行时确定某个变量是否属于该类型。类型擦除器在一定程度上有所帮助,但是很难使用多种橡皮擦类型。我的建议是为你需要处理的每种类型重载test方法。这也为您的代码增加了更多的类型安全性。

func test<S: Sub1, T>(_ s: S) where S.T == T

func test(_ s: Sub2)

上述解决方案无法正常运行,因为您拥有Super个元素的集合,并且需要根据实际类型执行某些操作。对于这种情况,可能的方法是在协议级别移动test方法,并在子协议中覆盖。

protocol Super {
    func test()
}

protocol Sub1: Super { associatedtype T }

protocol Sub2: Super {}

extension Sub1 {
    func test() { ... do stuff for Sub1 }
}

extension Sub2 {
    func test() { ... do stuff for Sub2 }
}

缺点是,构建者可以覆盖test,因此您将失去最初的实施。