【问题标题】:Swift generic collection of Element cannot convert to collection of AnyElement 的 Swift 通用集合无法转换为 Any 的集合
【发布时间】:2020-08-30 09:59:59
【问题描述】:

我遇到了一个我不明白的问题。 在我的项目中,我想使用一些自定义方法(例如来自服务器的更新)制作一组元素。但是当我尝试将所有这些集合分组到一个数组中时,我收到一个错误:“无法将 MyCollection<someElement> 类型的值转换为预期的参数类型 MyCollection<Any>

我不明白的是,与 Array 相同的代码正在工作...... Array 不是集合?

// My collection which would contain an update method
class MyCollection<Element> {
    var object:Element? = nil
}

let x = MyCollection<Int>()
var list = [MyCollection<Any>]()
list.append(x) //Cannot convert value of type 'MyCollection<In>' to expected argument type 'MyCollection<Any>'

let a = Array<Int>()
var lista = [Array<Any>]()
lista.append(a) //Doesn't get error at all...

我知道我可以使用特定类型的数组来做到这一点,但是通过将所有 MyCollection 分组到一个数组中,我希望使用如下代码:

func update() {
    for e in list { // array of MyCollection<Any>
        e.update()
    }
}

提前感谢您的帮助;)

【问题讨论】:

    标签: swift generics collections typing


    【解决方案1】:

    能够从SomeType&lt;Subtype&gt; 转换为SomeType&lt;Supertype&gt; 称为协方差。在 Swift 中,Array&lt;T&gt; is covariant on T by "compiler magic", and you can't do the same for your own types.

    如果存在从 T 到 U 的转换,类型检查器会硬编码从 Array 到 Array 的转换。 Optional 和 Dictionary 存在类似的规则。没有机制可以用您自己的类型执行此操作。

    您自己的泛型类型始终是不变的,这意味着只要TU 是不同的类型,SomeType&lt;T&gt;SomeType&lt;U&gt; 之间就永远不会发生转换。

    让我们想象一下如果允许MyCollection 上的转换会发生什么。你可以这样做:

    let myCollectionInt = MyCollection<Int>()
    let myCollectionAny: MyCollection<Any> = myCollectionInt // suppose you can do this
    myCollectionAny.object = "string" // myCollectionAny.object is of type Any?, so this should be ok
    

    我们将myCollectionAny.object 设置为“字符串”,但MyCollection 是一个引用类型,所以myCollectionInt.object 也应该是“字符串”。但是myCollectionInt.objectInt?

    当然,这种类型不安全也是数组的一个问题,但是语言设计者已经决定强制转换数组是一件很常见的事情,不允许它做起来比好事更难。

    【讨论】:

    • 非常感谢您的回答。对我来说,这个概念似乎深入地下室,我不确定我的编程技能是否高到足以理解所有这些的来龙去脉。这不是我第一次遇到通用结构/类类型检查器的麻烦......我将寻找一种不同的方式来做我需要的事情。感谢您的帮助;)
    • @TheSnowFox Forst Array 它不是一个类,它是一个结构。其次,您的班级不适合收藏。如果您实现了符合集合的适当泛型类型,您将获得与数组相同的行为。
    • @LeoDabus 我很确定该语言只对数组进行特殊处理,而不是对“任何Collection struct”进行特殊处理。例如,我尝试使用CollectionOfOne,但它没有按预期编译。 let a = CollectionOfOne(""); let b: CollectionOfOne&lt;Any&gt; = a
    • @Sweeper 在我看来,上面的问题是您试图将单个对象分配给集合。 gist.github.com/leodabus/aefeb8690377ee6ddccf075fffaeb036
    • @LeoDabus OP 有一个MyCollection&lt;Any&gt;s 数组,称为list,OP 正在尝试将MyCollection&lt;Int&gt; 添加到该数组中,因此从MyCollection&lt;Int&gt; 转换为MyCollection&lt;Any&gt;是需要的。我解释了为什么你永远不能用你自己的类型隐式地做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    相关资源
    最近更新 更多