我想在[String:SomeClass]类型的Dictionary中存储一个更专业的类型。这是一些说明我的问题的示例代码(也可以在https://swiftlang.ng.bluemix.net/#/repl/579756cf9966ba6275fc794a上使用):
class Thing<T> {} protocol Flavor {} class Vanilla: Flavor {} var dict = [String:Thing<Flavor>]() dict["foo"] = Thing<Vanilla>()
它产生错误ERROR at line 9, col 28: cannot assign value of type 'Thing<Vanilla>' to type 'Thing<Any>?'。
ERROR at line 9, col 28: cannot assign value of type 'Thing<Vanilla>' to type 'Thing<Any>?'
我已经尝试过强制转换,Thing<Vanilla>() as Thing<Flavor>但是会产生错误cannot convert value of type 'Thing<Vanilla>' to type 'Thing<Flavor>' in coercion。
Thing<Vanilla>() as Thing<Flavor>
cannot convert value of type 'Thing<Vanilla>' to type 'Thing<Flavor>' in coercion
我也尝试将Dictionary定义为type,[String:Thing<Any>]但这也没有任何改变。
[String:Thing<Any>]
如何在Thing不求助于平原的情况下创建不同s 的集合[String:AnyObject]?
Thing
[String:AnyObject]
我还应该提到该类Thing不是我定义的(实际上是关于BoltsSwift Task的),因此创建Thing没有类型参数的基类的解决方案不起作用。
Task
A Thing<Vanilla>不是Thing<Flavor>。Thing不是协变的。Swift中无法表达Thing协变。这有充分的理由。如果没有严格的规则就允许您要求的内容,则可以编写以下代码:
Thing<Vanilla>
Thing<Flavor>
func addElement(array: inout [Any], object: Any) { array.append(object) } var intArray: [Int] = [1] addElement(array: &intArray, object: "Stuff")
Int是的子类型Any,因此如果[Int]是的子类型[Any],则可以使用此函数将字符串追加到int数组。这打破了类型系统。不要那样做
Int
Any
[Int]
[Any]
根据您的实际情况,有两种解决方案。如果是值类型,则将其重新打包:
let thing = Thing<Vanilla>(value: Vanilla()) dict["foo"] = Thing(value: thing.value)
如果是引用类型,请在其旁边加上类型橡皮擦。例如:
// struct unless you have to make this a class to fit into the system, // but then it may be a bit more complicated struct AnyThing { let _value: () -> Flavor var value: Flavor { return _value() } init<T: Flavor>(thing: Thing<T>) { _value = { return thing.value } } } var dict = [String:AnyThing]() dict["foo"] = AnyThing(thing: Thing<Vanilla>(value: Vanilla()))
类型擦除器的具体信息可能会有所不同,具体取决于您的基础类型。
顺便说一句:关于此问题的诊断已经相当不错。如果您尝试addElement在Xcode 9中调用上述代码,则会得到以下信息:
addElement
Cannot pass immutable value as inout argument: implicit conversion from '[Int]' to '[Any]' requires a temporary
这告诉您的是,Swift愿意将[Int]您要求的位置[Any]作为数组的特殊情况传递给您(尽管这种特殊待遇并未扩展到其他泛型类型)。 但是 它只能通过制作数组的临时(不可变)副本来允许它。(这是另一个很难解释Swift性能的例子。在其他语言中看起来像“广播”的情况下,Swift可能会复制一个副本。或者可能不会。但是很难确定。)