Swift:通用集合的集合

时间:2015-10-23 17:59:39

标签: swift generics

我有一个基类ItemBase和一个类CollectionBase,其中的项目类型为ItemBase

我从这个ItemBase - PersonItemAnimalItem派生了两个类。

我使用相应的项目CollectionBasePersonCollectionAnimalCollection派生了两个类。

然后我创建了一个CollectionBase - ItemBase类型的数组。

现在我想将PersonCollectionAnimalCollection附加到数组中,但是我收到以下错误:

  

"无法指定类型' PersonCollection'的值输入   '数据收集"

如何定义集合数组,我可以根据CollectionBase - ItemBase附加项目?

class ItemBase {
}

class CollectionBase<T: ItemBase> {
  var Items = [T]()
}

class PersonItem: ItemBase {
}

class PersonCollection: CollectionBase<PersonItem> {
}

class AnimalItem: ItemBase {
}

class AnimalCollection: CollectionBase<AnimalItem> {
}

var collection = [CollectionBase<ItemBase>]()

// Error: Cannot assign value of type 'PersonCollection' to type 'DataCollection<ItemBase>
collection.append(PersonCollection())
// Error: Cannot assign value of type 'AnimalCollection' to type 'DataCollection<ItemBase>
collection.append(AnimalCollection())

2 个答案:

答案 0 :(得分:2)

首先,您的示例包含一些关于编译器(正确)无法接受的类型系统的矛盾陈述。

为了那个时刻&#39;,请阅读variance and contravariance on Wikipedia。否则,继续阅读。

你的例子在这里失败的原因是

var collection = [CollectionBase<ItemBase>]()

定义了一个类数组,您可以使用ItemBase类的项访问和更新Items成员属性。

然后,您尝试追加违反此要求的数组元素PersonCollection() - 它不允许向其项目成员添加ItemBase。

其次,因为

  

PersonCollection继承自ItemBase

您正在阅读以下内容:

  

SomeGeneric&LT; PersonCollection&GT;继承自SomeGeneric&lt; ItemBase&gt;

虽然这对你来说可能是完全合理的,但是快速语言中没有任何东西可以实现这一点。

你可以在这里合理地指出 swift集合类似乎可以正常管理 - 如下所示:

class ItemBase {
}

class PersonItem: ItemBase {
}

class AnimalItem: ItemBase {
}

var collection = [Array<ItemBase>]()

collection.append([PersonItem]())

它确实如此,但不幸的是它这样做是因为swift语言对内置集合类型(如Array)有特殊规则。 As far as I know你不能仅使用快速代码独立实现Array。

那么如何处理呢?

在您解决设计中的上述不一致之前,您不能。但是,我认为这些功能只是根据您所使用的语言解决问题的方法。

您可以使用swift的内置Array类。

或者您可以定义一个在基础上不通用的不同继承层次结构:

例如 - 在基础上使用协议(或类),它肯定适用于ItemBase对象(没有关联的类型要求)。

protocol ItemCollection {
    var items:[ItemBase] { get }
}

class ThingCollection<Thing:ItemBase>:ItemCollection {
    var things:[Thing] = []
    var items:[ItemBase] {
        return things
    }
}

typealias PersonCollection = ThingCollection<PersonItem>


var itemCollection:[ItemCollection] = []

itemCollection.append(PersonCollection())

答案 1 :(得分:0)

为什么需要额外的间接?有什么问题:

class ItemBase {
}

class PersonItem: ItemBase {
}

class AnimalItem: ItemBase {
}

var collection = [ItemBase]()
collection.append(PersonItem())
collection.append(AnimalItem())

或者:

class ItemBase {
}

class PersonItem: ItemBase {
}

class AnimalItem: ItemBase {
}

var collection = [[ItemBase]]()
collection.append([PersonItem]())

还有可能:

class ItemBase {
}

class PersonItem: ItemBase {
}

class AnimalItem: ItemBase {
}

class CollectionBase<T: ItemBase> {
    var Items = [T]()
}

class PersonCollection: CollectionBase<PersonItem> {
}

class AnimalCollection: CollectionBase<AnimalItem> {
}

let personCollection = PersonCollection()
personCollection.Items.append(PersonItem())

但我认为你想要的额外间接在Swift中是不可能的。你可以解决它,但是失去了严格的类型安全性:

var collection = [AnyObject]()
collection.append(PersonCollection())
collection.append(AnimalCollection())

if collection[0] is PersonCollection {
    // ...
}