一尘不染

在Swift中,如何转换为具有关联类型的协议?

swift

在下面的代码中,我想测试是否xSpecialController。如果是的话,我想currentValue作为SpecialValue。你怎么做到这一点?如果不使用强制转换,则使用其他技术。

那里的最后一行不会编译。错误是: 协议“ SpecialController”仅具有通用要求或关联类型要求,因此只能用作通用约束。

protocol SpecialController {
    associatedtype SpecialValueType : SpecialValue
    var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController {  // does not compile

阅读 248

收藏
2020-07-07

共1个答案

一尘不染

不幸的是,Swift当前不支持将具有关联类型的协议用作实际类型。但是,从技术上讲这对于编译器是可行的。并且很可能在该语言的未来版本中实现

在您的情况下,一个简单的解决方案是定义一个“影子协议”,该影子协议SpecialController派生自该影子协议,并允许您currentValue通过协议要求进行访问,而协议要求将其擦除:

// This assumes SpecialValue doesn't have associated types – if it does, you can
// repeat the same logic by adding TypeErasedSpecialValue, and then using that.
protocol SpecialValue {
  // ...
}

protocol TypeErasedSpecialController {
  var typeErasedCurrentValue: SpecialValue? { get }
}

protocol SpecialController : TypeErasedSpecialController {
  associatedtype SpecialValueType : SpecialValue
  var currentValue: SpecialValueType? { get }
}

extension SpecialController {
  var typeErasedCurrentValue: SpecialValue? { return currentValue }
}

extension String : SpecialValue {}

struct S : SpecialController {
  var currentValue: String?
}

var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController {
  print(sc.typeErasedCurrentValue as Any) // Optional("Hello World!")
}
2020-07-07