【问题标题】:Swift - Inherited Protocol Associated Type ErasureSwift - 继承协议关联类型擦除
【发布时间】:2018-03-04 16:19:52
【问题描述】:

我有 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 具有关联类型,因此我不能使用“as?Sub1”或 is 运算符。现在我试图擦除类型以便能够转换它。如果除了类型擦除之外还有其他方法可以实现这一点,我对新事物持开放态度

标签: swift swift-protocols


【解决方案1】:

由于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 }
}

缺点是conformers可以覆盖test,因此你会失去原来的实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多