In Swift, how to cast to protocol with associated type?

前端 未结 3 2029
暗喜
暗喜 2020-12-14 02:22

In the following code, I want to test if x is a SpecialController. If it is, I want to get the currentValue as a SpecialValue

3条回答
  •  悲&欢浪女
    2020-12-14 02:46

    Unfortunately, Swift doesn't currently support the use of protocols with associated types as actual types. This however is technically possible for the compiler to do; and it may well be implemented in a future version of the language.

    A simple solution in your case is to define a 'shadow protocol' that SpecialController derives from, and allows you to access currentValue through a protocol requirement that type erases it:

    // 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!")
    }
    

提交回复
热议问题