首先協(xié)變(Covariance)和逆變(contravariance),這倆概念不是TS特有的,很多有類型系統(tǒng)的語言都有一樣的概念,比如C#,JAVA等。要理解這兩個概念,讓我們先建立幾個類,然后再詳細說明,如下:
代碼很直觀,建立了3個類,動物,狗,黃狗,它們之間的繼承關系是,動物(Animal)類是基類,狗(Dog)繼承自動物類,黃狗(YellowDog)繼承自狗類。Animal <- Dog <- YellowDog 它們每個類都有各自特有的屬性。
接下來,我們來為每個類創(chuàng)建一個實例對象:
協(xié)變(Covariance)
根據(jù)微軟的解釋:協(xié)變是使您能夠使用比最初指定更多的派生類型。這是什么意思?其實就是指,派生類型的值可以安全的賦給基類型(繼承自的類型),而反過來就不行。
比如本例中,黃狗的實例,就可以賦值給類型為狗或動物的變量,狗的實例可以賦值給動物類型的變量,但反過來,狗的實例,就不可以賦值給黃狗類型的變量,如下:
我覺得這也可以理解,因為這樣的賦值是安全的。屬性多的實例,賦值給屬性少的類型,不會丟失數(shù)據(jù)。黃狗類包含了動物類所有的成員,所以當黃狗對象賦值給動物類型時,動物類型的每個字段屬性都可以被正常賦值,如果反過來,用動物實例對象給黃狗類型賦值,那動物對象中就不存在黃狗對象所需要的字段,視為不安全賦值,所以編譯報錯。
逆變(contravariance)
也是根據(jù)微軟的解釋:跟協(xié)變正好相反,逆變使您能夠使用比最初指定的更通用(較少派生)的類型。
這通常發(fā)生在函數(shù)類型的參數(shù)中,看下面的代碼:
我們定義了三個函數(shù)類型,然后為每個函數(shù)類型定義了一個函數(shù)的實例。
接下來,我們定義了一個函數(shù),它的參數(shù)是一個FuncDog的函數(shù)類型。讓我們看看把每個函數(shù)傳進來會有什么結果,
現(xiàn)在反而是 funYellowDog 參數(shù)報錯了,因為它是繼承自Dog,跟協(xié)變相反,所以它會報錯。那要怎么理解這個呢?為啥會這樣,我是這么理解的,
讓我們改一下這個函數(shù),讓它做點事:
因為傳入的函數(shù)參數(shù)終究還是要被調用的,按理它是需要一個狗的對象,所以我們實例化一個dog對象,然后調用 func(dog) ,這時如果使用 FuncAnimal 類型的函數(shù),沒有問題,因為它需要的參數(shù)是 Animal 類型,所以dog可以賦值給它。正好又符合了協(xié)變。
但如果這里允許傳入 FuncYellowDog 類型的函數(shù),那當它調用的時候,dog就想當于要賦值給 YellowDog 類型的變量,這就又是不安全的賦值。跟協(xié)變里面的錯誤是一樣的。所以就禁止這樣做了。
總結
這里有點饒啊,最好大家可以自己上手試試,我覺得可以想明白的。感謝閱讀,發(fā)現(xiàn)錯誤請指正。