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

查看:39
本文介绍了如何存储 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>() 

它在第 9 行第 28 列产生错误 ERROR: cannot assign value of type 'Thing<Vanilla>'输入'Thing<Any>?'.

It produces the error ERROR at line 9, col 28: cannot assign value of type 'Thing<Vanilla>' to type 'Thing<Any>?'.

我尝试将 Thing<Vanilla>() 转换为 Thing 但这会产生错误 cannot convert value of type 'Thing<Vanilla>'输入事物<风味>"在强制中.

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.

我也尝试将 Dictionary 定义为 [String:Thing<Any>] 类型,但这也不会改变任何内容.

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的),所以解决方法是创建一个的基类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 愿意在你要求 [Any] 的地方传递 [Int] 作为数组的特例(尽管这个特殊的处理未扩展到其他泛型类型).但是它只会通过制作数组的临时(不可变)副本来允许它.(这是另一个很难推断 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&lt;ClassImplementingProtocol&gt; 类型的值在 Swift 中的 [String:Class&lt;Protocol&gt;] 类型的字典中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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