实现泛型的自定义类的数组,不允许具有子类通用的自定义类 [英] Array of custom class implementing generics not allowing custom class with subclassed generic

查看:144
本文介绍了实现泛型的自定义类的数组,不允许具有子类通用的自定义类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下情况

class Human {}
class Child: Human {}
class Person<T: Human> {}

var people = [Person<Human>]()
people.append(Person<Child>())

还行 people.append(Person< Child>())我收到错误

cannot convert value of type 'Person<Child>' to expected argument type 'Person<Human>'

这很奇怪,因为做以下工作(看起来情况相同)

This is really strange as doing the following works (which seems to be an identical situation)

var myArray = [Array<UIView>]()
myArray.append(Array<UIImageView>())

有人会理解为什么一种方式有效而不是另一种方式吗?

Would anyone have an understanding of why one way works and not the other?

推荐答案

实际上你并没有足够强烈地提起诉讼。定义:

Actually you're not putting the case strongly enough. Define:

class Human {}
class Child: Human {}
struct Holder<T> {}

我使Holder成为一个结构,所以没有人可以指责我们作弊:Array是一个结构,持有人是一个结构。我删除了对占位符的限制,将所有内容都缩减为最简单的形式。

I made Holder a struct so no one can accuse us of cheating: Array is a struct, Holder is a struct. And I took away your constraint on the placeholder, reducing everything to the simplest possible form.

现在只需指定一个Child数组,其中包含一个Human数组:

Now just assign an array of Child where an array of Human is expected:

var arr = Array<Human>()
arr = Array<Child>()

好的。现在尝试使用持有人:

Fine. Now try it with a Holder:

var holder = Holder<Human>()
holder = Holder<Child>() // error

并行现在看起来很完美:数组是一个结构,Holder是一个结构,我们所做的就是尝试多态分配。那么问题是什么?

The parallelism now appears perfect: Array is a struct, Holder is a struct, and all we're doing is trying to assign polymorphically. So what's the problem?

你可能已经怀疑的问题是你不是Apple。 Apple编写代码,因此他们可以在参数化类型上定义Array和类似的类型 covariant 。但它不是该语言的自动功能 - 也就是说,对于泛型一般来说并非如此。特别是,不能为定义的类型做到这一点。

The problem, as you have probably already suspected, is that you are not Apple. Apple writes the code, so they get to define Array and similar types as covariant on the parametrized type. But it isn't an automatic feature of the language — that is, it is not true for generics in general. And in particular, you don't get to do that for types you define.

所以Apple的数组是协变,但你的持有人(或人)不是,并且没有什么可以让你改变协方差。

So Apple's Array is covariant, but your Holder (or Person) is not, and there's nothing that allows you to switch covariance on.

你可以看到为什么数组是协变的。这是一个非常特殊的案例。数组是对象的集合。 Apple知道,例如,Child对象的数组实际上也是Human对象的数组,因为每个Child都是Human(多态)。所以他们已经为数组实现了协方差,以确保这样做。

You can see why Array is covariant. It is a very special case. An array is a collection of objects. Apple knows that an array of, say, Child objects is also in fact an array of Human objects, because every Child is a Human (polymorphism). So they have implemented covariance for arrays, to ensure that this is so.

但是对于你的人或我的持有人没有这样的保证。 Swift不知道你打算用占位符T做什么你可能会想到用替换替换的情况 Holder< Human> 预计错误。所以Apple没有做出任何假设。

But there is no such guarantee about your Person or my Holder. Swift doesn't know what you intend to do with the placeholder T. You can probably think of cases where substituting a Holder<Child> where a Holder<Human> is expected would be wrong. So Apple makes no assumptions in that direction.

我应该补充一点,区分以下内容非常重要:

I should add that it's important to distinguish the following:

class Human {}
class Child: Human {}
struct Holder<T> {
    let thing : T
}
let holder : Holder<Human> = Holder(thing:Child()) // fine

这是合法的,但它什么都没有做我们一直在谈论的事情。此处只涉及一种通用类型: Holder< Human> 。我们所做的只是将一个Child分配到 thing ,其中需要Human。这是一种很好的老式非泛型多态性。但您仍然无法将 Holder< Human> 转换为 Holder< Child> ,即使东西 是一个孩子,你仍然无法分配持有人< Child> 其中a 预计持有人< Human>

That's legal, but it has nothing whatever to do with what we've been talking about. Only one generic type is involved here: Holder<Human>. All we're doing is assigning a Child into thing, where a Human is expected. That's good old-fashioned non-generic polymorphism. But you still can't cast a Holder<Human> down to a Holder<Child>, even if thing is a Child, and you still can't assign a Holder<Child> where a Holder<Human> is expected.

这篇关于实现泛型的自定义类的数组,不允许具有子类通用的自定义类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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