实现generics的自定义类的数组,不允许具有子类通用的自定义类
我有以下情况
class Human {} class Child: Human {} class Person {} var people = [Person]() people.append(Person())
但就行了people.append(Person())
我收到错误了
cannot convert value of type 'Person' to expected argument type 'Person'
做以下工作真的很奇怪(这似乎是一个相同的情况)
var myArray = [Array]() myArray.append(Array())
有人会理解为什么一种方式有效而不是另一种方式?
实际上你并没有足够强烈地表达这个案子。 定义:
class Human {} class Child: Human {} struct Holder {}
我使Holder成为一个结构,所以没有人可以指责我们作弊:Array是一个结构,Holder是一个结构。 并且我在占位符上删除了约束,将所有内容减少到最简单的forms。
现在只需指定一个Child数组,其中包含一个Human数组:
var arr = Array() arr = Array()
精细。 现在尝试使用持有人:
var holder = Holder() holder = Holder() // error
并行性现在看起来很完美:Array是一个结构,Holder是一个结构,我们所做的就是尝试多态分配。 所以有什么问题?
正如您可能已经怀疑的那样,问题在于您不是Apple。 Apple编写代码,因此他们可以将Array和类似的类型定义为参数化类型的协变 。 但它不是该语言的自动特征 – 也就是说,对于generics一般来说并非如此。 特别是,对于您定义的类型, 您无法做到这一点。
所以Apple的Array是协变的,但你的Holder(或Person)不是,并且没有任何东西允许你切换协方差。
你可以看到为什么 Array是协变的。 这是一个非常特殊的案例。 数组是对象的集合。 Apple知道,例如,Child对象的数组实际上也是Human对象的数组,因为每个Child都是Human(多态)。 因此,他们已经为数组实现了协方差,以确保这样做。
但是对于你的人或我的持有人没有这样的保证。 Swift不知道你打算用占位符T做什么 。你可以想到用一个Holder
取代Holder
所谓的 错误的情况 。 所以Apple没有在这个方向做出任何假设。
我应该补充说,区分以下内容很重要:
class Human {} class Child: Human {} struct Holder { let thing : T } let holder : Holder = Holder(thing:Child()) // fine
这是合法的,但它与我们一直在谈论的内容毫无关系。 这里只涉及一种通用类型: Holder
。 我们所做的就是将一个孩子分配到一个人类所需的thing
中。 这是一种很好的老式非generics多态性。 但是你仍然无法将Holder
投下一个Holder
Holder
,即使thing
是一个孩子,你仍然不能指定一个Holder
是Holder
。