Swift - 继承协议类型擦除

问题描述 投票:0回答:1

我有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中没有任何通用参数。有人有想法,我怎么能解决这个问题?

swift swift-protocols
1个回答
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,因此你将失去最初的实现。

© www.soinside.com 2019 - 2024. All rights reserved.