2016-03-04 19 views
2

我有以下情形尚未阵列的定制类实现仿制药不允许自定义类的子类通用

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>' 

错误这是真的很奇怪做了以下工作(似乎是相同的情况)

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

任何人都会理解为什么一种方法可行,而不是另一种?

回答

5

其实你没有足够强调。定义:

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

我做了一个支架结构,所以没有人可以指责我们欺骗:数组是一个结构,持有人是一个结构。我取消了对占位符的限制,将所有内容都缩小为最简单的形式。

现在只需指定儿童的数组,其中人类的阵列预计:

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

精细。现在,随着持有人尝试:

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

的并行现在看起来完美:数组是一个结构,持有人是一个结构,而我们正在做的是想多态分配。所以有什么问题?

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

所以Apple的数组是协变的,但是你的Holder(或Person)不是,并且没有什么能让你切换协方差。

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

但是对于您的人或我的持有人没有这样的保证。 Swift不知道你打算如何用占位符T做什么。您可以考虑使用Holder<Child>代替Holder<Human>的情况,这可能是错误。所以苹果公司在这方面不做任何假设。


我要补充,这区分下列事项:

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

这是合法的,但它没有任何关系与我们一直在谈论。这里只涉及一种泛型:Holder<Human>。我们正在做的是将一个孩子分配到thing,其中一个人是预期的。这是非常老式的非泛型多态。但你仍然无法投出Holder<Human>下降到Holder<Child>,即使thing一个孩子,你仍然无法分配Holder<Child>其中Holder<Human>预期。

+1

并且看到这个关于这个话题的经典文章:http://nomothetis.svbtle.com/type-variance-in-swift – matt