在Swift中,如何使用关联类型转换为协议? [英] In Swift, how to cast to protocol with associated type?
问题描述
在下面的代码中,我想测试 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屋!