我剛剛學過Scala。現在我對逆變和協變感到困惑。Scala中的協變性與協方差
從這個page,我學到下面的東西:
協方差
也許亞型的最明顯的特徵是在表達一個更小的類型的值來代替一個更廣泛類型的值的能力。例如,假設我有一些類型Real
,Integer <: Real
和一些不相關的類型Boolean
。我可以定義一個函數is_positive :: Real -> Boolean
,它的值爲Real
,但我也可以將此函數應用於Integer
(或任何其他子類型爲Real
)的值。用較窄(後代)類型替換較寬(祖先)類型稱爲covariance
。 covariance
的概念允許我們編寫泛型代碼,並且在推理面向對象的編程語言中的繼承和函數式語言中的多態時非常有用。
但是,我也看到從其他地方的東西:
scala> class Animal
defined class Animal
scala> class Dog extends Animal
defined class Dog
scala> class Beagle extends Dog
defined class Beagle
scala> def foo(x: List[Dog]) = x
foo: (x: List[Dog])List[Dog] // Given a List[Dog], just returns it
scala> val an: List[Animal] = foo(List(new Beagle))
an: List[Animal] = List([email protected])
參數foo
x
爲contravariant
;它預計類型List[Dog]
類型的論據,但我們給它一個List[Beagle]
,這沒關係
[我認爲是第二個例子也應該證明Covariance
。因爲從第一個例子中,我瞭解到「將此函數應用於Integer
類型的值(或任何其他子類型Real
)」。因此相應地,我們在這裏將此函數應用於List[Beagle]
(或List[Dog]
的任何其他子類型)類型的值。但令我驚訝的是,第二個例子證明Cotravariance
]
我認爲兩個人在說同一件事,但一個證明Covariance
和其他Contravariance
。我也看到了this question from SO。但是我仍然感到困惑。我錯過了什麼或者其中一個例子是錯誤的?
很好的解釋。儘管'groomAnyAnimal'的返回類型應該是'Dog'來插入它,因爲函數在它們的返回類型中是協變的並且僅在它們的參數類型中是逆變的。 – 2014-12-11 04:02:36
@stew你認爲第二個例子的陳述有些不對嗎? – CSnerd 2014-12-11 04:09:46
@CSnerd在你的第二個例子中,你想知道'x'是協變還是逆變。然而,正如燉菜所提到的,方差對於是否可以傳遞需要超類型的子類型沒有任何關係(參見[Liskov Substitution Principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle))。在第二個例子中唯一的協變是List,因此'List [Beagle]'是List [Dog]的一個子類型。 – 2014-12-11 04:17:46