我有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中没有任何通用参数。 有没有人有想法,我怎么解决这个问题?
答案 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
,因此您将失去最初的实施。