在Swift中,如何使用关联类型转换为协议? [英] In Swift, how to cast to protocol with associated type?

查看:141
本文介绍了在Swift中,如何使用关联类型转换为协议?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



最后一行不能编译。有错误的是: ProtocolSpecialController只能用作通用约束,因为它具有Self或相关类型的要求。

  protocol SpecialController {
associatedtype SpecialValueType:SpecialValue
var currentValue:SpecialValueType? {get}
}
...
var x:AnyObject = ...
如果让sc = x as? SpecialController {//不会编译


解决方案

当前不支持使用与关联类型相关的协议作为实际类型。然而,这对编译器来说在技术上是可行的;而且它可能会在未来的版本中实现语言。

在你的情况下,一个简单的解决方案是定义一个'影子协议', SpecialController 派生自并允许你通过一个协议要求来访问 currentValue ,类型会将其擦除:

  / /这假设SpecialValue没有关联类型 - 如果是的话,可以通过添加TypeErasedSpecialValue重复
//相同的逻辑,然后使用它。
协议SpecialValue {
// ...
}

协议TypeErasedSpecialController {
var typeErasedCurrentValue:SpecialValue? {get}
}

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

扩展SpecialController {
var typeErasedCurrentValue:SpecialValue? {return currentValue}
}

扩展字符串:SpecialValue {}
$ b $ struct S:SpecialController {
var currentValue:String?
}

var x:Any = S(currentValue:Hello World!)
如果让sc = x as? TypeErasedSpecialController {
print(sc.typeErasedCurrentValue as Any)//可选(Hello World!)
}


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. How do you do this? If not with a cast, then some other technique.

The last line there won't compile. There error is: Protocol "SpecialController" can only be used as a generic constraint because it has Self or associated type requirements.

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

解决方案

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

这篇关于在Swift中,如何使用关联类型转换为协议?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆