如何在Swift中的types为的Dictionary中存储Class <ClassImplementingProtocol>types的值?
我想在一个types为[String:SomeClass]的字典中存储一个更专门化的types。 下面是一些示例代码,说明我的问题(也可以在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 。 
 我也试过把字典定义为types[String:Thing<Any>]但是也不会改变任何东西。 
 如何创build一个不同的Thing的集合而不诉诸普通的[String:AnyObject] ? 
 我还应该提到Thing类不是由我定义的(实际上它是关于BoltsSwift Task ),所以没有types参数创buildThing基类的解决scheme不起作用。 
 一Thing<Vanilla>不是一Thing<Flavor> 。  Thing不是协变的。  Swift没有办法expressionThing是协变的。 这有很好的理由。 如果你所要求的是没有经过周密的规定,我可以写下面的代码: 
 func addElement(array: inout [Any], object: Any) { array.append(object) } var intArray: [Int] = [1] addElement(array: &intArray, object: "Stuff") 
  Int是Any的子types,所以如果[Int]是[Any]的子types,我可以使用这个函数将string附加到int数组中。 这打破了types系统。 不要这样做。 
根据你的具体情况,有两种解决scheme。 如果它是一个值types,然后重新打包它:
 let thing = Thing<Vanilla>(value: Vanilla()) dict["foo"] = Thing(value: thing.value) 
如果是参考types,请使用橡皮擦来装箱。 例如:
 // 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())) 
橡皮擦的细节可能会根据您的基础types而有所不同。
 顺便说一句:关于这方面的诊断已经相当不错了。 如果你尝试在Xcode 9中调用上面的addElement ,你会得到这个: 
 Cannot pass immutable value as inout argument: implicit conversion from '[Int]' to '[Any]' requires a temporary 
 这是告诉你的是,Swift愿意把你所要求的[Int]作为数组的特例(尽pipe这个特殊的处理没有扩展到其他generics)。  但它只会通过创build一个临时(不可变)的数组副本来实现。  (这是另外一个很难说明Swift性能的例子,在其他语言中看起来像“cast”的情况下,Swift可能会做一个副本,或者它不可能,很难确定)。 
 解决这个问题的一个办法是给Thing添加一个初始化器,并创build一个可以容纳一个Vanilla物体的Thing<Flavor> 。 
它看起来像这样:
 class Thing<T> { init(thing : T) { } } protocol Flavor {} class Vanilla: Flavor {} var dict = [String:Thing<Flavor>]() dict["foo"] = Thing<Flavor>(thing: Vanilla())