如何存储 Class<ClassImplementingProtocol> 类型的值?在 Swift 中类型为 [String:Class<Protocol>] 的字典中? [英] How do I store a value of type Class&lt;ClassImplementingProtocol&gt; in a Dictionary of type [String:Class&lt;Protocol&gt;] in Swift?

查看:21
本文介绍了如何存储 Class<ClassImplementingProtocol> 类型的值?在 Swift 中类型为 [String:Class<Protocol>] 的字典中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在类型为 [String:SomeClass] 的字典中存储更专业的类型.这是一些说明我的问题的示例代码(也可以在 https://swiftlang.ng.bluemix.net/#/repl/579756cf9966ba6275fc794a):

I want to store a more specialized type in a Dictionary of type [String:SomeClass]. Here is some sample code illustrating my problem (also available to play with at 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'输入Thing?".

我尝试将 Thing() 转换为 Thing 但这会产生错误 cannot convert value of type 'Thing'输入'Thing'强制.

I've tried casting Thing<Vanilla>() as Thing<Flavor> but that produces the error cannot convert value of type 'Thing<Vanilla>' to type 'Thing<Flavor>' in coercion.

我也尝试将字典定义为 [String:Thing] 类型,但这也没有改变任何东西.

I've also tried to define the Dictionary as type [String:Thing<Any>] but that doesn't change anything either.

如何在不诉诸普通 [String:AnyObject] 的情况下创建不同 Thing 的集合?

How do I create a collection of different Things without resorting to plain [String:AnyObject]?

我还应该提到,Thing 类不是我定义的(实际上它是关于 BoltsSwift Tasks),因此创建 Thing 的基类的解决方案code>Thing 没有类型参数不起作用.

I should also mention that the class Thing is not defined by me (in fact it's about BoltsSwift Tasks), so the solution to create a base class of Thing without a type parameter doesn't work.

推荐答案

Thing 不是 Thing.Thing 不是协变的.在 Swift 中没有办法表达 Thing 是协变的.这有充分的理由.如果你的要求在没有仔细规则的情况下被允许,我将被允许编写以下代码:

A Thing<Vanilla> is not a Thing<Flavor>. Thing is not covariant. There is no way in Swift to express that Thing is covariant. There are good reasons for this. If what you were asking for were allowed without careful rules around it, I would be allowed to write the following code:

func addElement(array: inout [Any], object: Any) {
    array.append(object)
}

var intArray: [Int] = [1]
addElement(array: &intArray, object: "Stuff")

IntAny 的子类型,所以如果 [Int][Any] 的子类型,我可以使用这个函数将字符串附加到一个 int 数组.这打破了类型系统.不要那样做.

Int is a subtype of Any, so if [Int] were a subtype of [Any], I could use this function to append strings to an int array. That breaks the type system. Don't do that.

根据您的具体情况,有两种解决方案.如果是值类型,则重新打包:

Depending on your exact situation, there are two solutions. If it is a value type, then repackage it:

let thing = Thing<Vanilla>(value: Vanilla())
dict["foo"] = Thing(value: thing.value)

如果是引用类型,请使用类型橡皮擦将其框起来.例如:

If it is a reference type, box it with a type eraser. For example:

// 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()))

类型橡皮擦的细节可能因您的底层类型而异.

The specifics of the type eraser may be different depending on your underlying type.

顺便说一句:围绕这个的诊断已经变得非常好.如果您尝试在 Xcode 9 中调用上面的 addElement,您会得到:

BTW: The diagnostics around this have gotten pretty good. If you try to call my addElement above in Xcode 9, you get this:

Cannot pass immutable value as inout argument: implicit conversion from '[Int]' to '[Any]' requires a temporary

这告诉你的是,Swift 愿意传递 [Int] 在你要求 [Any] 的地方作为数组的特殊情况(尽管这个特殊处理未扩展到其他泛型类型).但是它只会通过制作数组的临时(不可变)副本来允许它.(这是另一个很难推断 Swift 性能的例子.在其他语言中看起来像是强制转换"的情况下,Swift 可能会复制.也可能不会.很难确定.)

What this is telling you is that Swift is willing to pass [Int] where you ask for [Any] as a special-case for Arrays (though this special treatment isn't extended to other generic types). But it will only allow it by making a temporary (immutable) copy of the array. (This is another example where it can be hard to reason about Swift performance. In situations that look like "casting" in other languages, Swift might make a copy. Or it might not. It's hard to be certain.)

这篇关于如何存储 Class<ClassImplementingProtocol> 类型的值?在 Swift 中类型为 [String:Class<Protocol>] 的字典中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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