swift:具有不同泛型类型的AnyCollection

vfh0ocws  于 2023-01-16  发布在  Swift
关注(0)|答案(1)|浏览(126)
AnyCollection([1, 2, 3]) // AnyCollection<Int>
AnyCollection(["a", "b", "c"]) // AnyCollection<String>

这两个AnyCollection非常棒,但是它们具有不同的泛型类型,即IntString
但我仍然可以将这两个AnyCollection添加到单个数组中,如下所示

// [AnyCollection<Any>]
let array = [AnyCollection([1, 2, 3]), AnyCollection(["a", "b", "c"])]

我不明白这两个AnyCollection发生了什么。
为什么可以从StringInt转换为Any
我自己写了一些代码来创建一个。

// ❌ Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
// Contains AnyMyCollection<String> && AnyMyCollection<Int> at a single collection.
var collections = [AnyMyCollection(Sports()), AnyMyCollection(Animals()), AnyMyCollection(Digits())]

protocol MyCollection<Element> {
    associatedtype Element
    func allValues() -> [Element]
}

// MARK: - AnyMyCollection

struct AnyMyCollection<Element> {
    internal var _box: _AnyMyCollectionBase<Element>
    
    init<C: MyCollection>(_ base: C) where C.Element == Element {
        self._box = _MyCollectionBox(base)
    }
}

extension AnyMyCollection: MyCollection {
    func allValues() -> [Element] {
        _box.allValues()
    }
}

final class _MyCollectionBox<Base: MyCollection>: _AnyMyCollectionBase<Base.Element> {
    init(_ base: Base) {
        _base = base
    }
    
    private var _base: Base
    override func allValues() -> [Base.Element] {
        _base.allValues()
    }
}

class _AnyMyCollectionBase<Element>: MyCollection {
    func allValues() -> [Element] {
        return []
    }
}

// MARK: - Diffrent Types of My Collection

struct Animals: MyCollection {
    typealias Element = String
    func allValues() -> [Element] {
        ["Monkey", "Tiger", "Lion"]
    }
}

struct Sports: MyCollection {
    typealias Element = String
    func allValues() -> [Element] {
        ["Basketball", "Football", "Baseball"]
    }
}

struct Digits: MyCollection {
    typealias Element = Int
    func allValues() -> [Element] {
        [1, 2, 3, 4, 5]
    }
}

我尝试采用相同的技术,但失败了,因为AnyMyCollection中元素的类型不相同。

yb3bgrhw

yb3bgrhw1#

简单的解释是,你不是苹果。
泛型一般不会协变参数化类型,而且你无法创建一个 * 协变参数化类型的泛型。* 但是Apple可以。*
为了更简单地理解这一点,考虑一下Array。它是一个泛型。如果你有两个类,一个类和它的子类,你可以合并它们中每一个的数组:

class MyClass {}
    class MySubclass: MyClass {}

    let arr1 = [MyClass()]
    let arr2 = [MySubclass()]

    let arr3 = [arr1, arr2] // [[MyClass]]

编译器接受这一点;它将得到的组合视为超类Array<Array<MyClass>>的数组的数组,因此对于Apple来说,Array<MySubclass>被视为Array<MyClass>的子类。
但是现在试着用你自己的仿制药来做,你做不到:

class MyGeneric<T> {}

    let g1 = MyGeneric<MyClass>()
    let g2 = MyGeneric<MySubclass>()

    let arr4 = [g1, g2] // error

编译器不会神奇地将其视为Array<MyGeneric<MyClass>>,因为 your 泛型不是协变的。
总有一些语言提案坐在那里,希望让我们普通人能够制造协变泛型,但到目前为止,还没有一个提案进入语言。

相关问题