2016-03-04 59 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