在以下代码中,我想测试x
是否为SpecialController
。如果是,我想将currentValue
作为SpecialValue
。你怎么做到这一点?如果不是演员,那么其他一些技巧。
最后一行不会编译。错误是:协议“SpecialController”只能用作通用约束,因为它具有Self或关联类型要求。
protocol SpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
...
var x: AnyObject = ...
if let sc = x as? SpecialController { // does not compile
答案 0 :(得分:14)
不幸的是,Swift目前不支持使用具有相关类型的协议作为实际类型。但是编译器要做is technically possible;它may well be implemented in a future version of the language。
在您的情况下,一个简单的解决方案是定义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!")
}
答案 1 :(得分:1)
[已修改:: SpecialValue
,而不是= SpecialValue
]
这是不可能的。 SpecialValueController
是一个"不完整的类型"从概念上讲,编译器无法知道。 SpecialValueType
,虽然受 SpecialValue
约束,但在任何采用类确定之前都不知道它。所以它是一个真正的占位符,信息不足。 as?
- 无法检查。
你可以有一个基类,SpecialController
采用具体类型的SpecialValueController
,并且有多个子类继承自采用类,如果你&#39 ;仍然在寻求一定程度的多态性。
答案 2 :(得分:0)
这不起作用,因为SpecialController
不是单一类型。您可以将关联类型视为一种泛型。其中SpecialController
为SpecialValueType
的{{1}}与Int
完全不同,其SpecialController
为SpecialValueType
,就像String
与Optional<Int>
完全不同。
因此,转换为Optional<String>
没有任何意义,因为这会掩盖关联的类型,并允许您使用(例如)SpecialValueType
及其SpecialController
{1}} SpecialValueType
Int
,SpecialController
的{{1}}为SpecialValueType
。
正如编译器所建议的那样,String
可以使用的唯一方法是作为通用约束。您可以使用SpecialController
上的泛型函数,其约束条件T
必须是T
。 SpecialController
的域现在涵盖T
的所有具体类型,例如SpecialController
关联类型和Int
。对于每种可能的关联类型,都有一个不同的String
,以及一个不同的SpecialController
。
进一步提出T
类比。想象一下,如果你想要做的事情是可能的。这将是这样的:
Optional<T>