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