讓我們來看看你提到的第一個例子。 考慮,我們有:
class Fruit
class Apple extends Fruit
class Banana extends Fruit
class Bhanu[-A](val m: List[A]) // abstract removed for simplicity
由於Bhanu
是contravatiant Bhanu[Fruit] <: Bhanu[Apple]
這樣你就可以做到以下幾點:
val listOfApples = new List[Apple](...)
val listOfFruits = listOfApples // Since Lists are covariant in Scala
val a: Bhanu[Fruit] = new Bhanu[Fruit](listOfFruits)
val b: Bhanu[Banana] = a // Since we assume Bhanu is contravariant
val listOfBananas: List[Banana] = b.m
val banana: Banana = listOfBananas(0) // TYPE ERROR! Here object of type Banana is initialized
// with object of type Apple
所以Scala編譯器的限制,保護我們免受這種錯誤的協變位置使用逆變類型參數。
對於第二個問題,我們來看一下這個例子。考慮到我們擁有的功能:
val func1: Function1[Tennis,Int] = ...
如果Function1[Tennis,Int] <: Function1[Sport,Int]
其中Tennis <: Sport
你提出比我們能做到以下幾點:
val func2: Function1[Sport,Int] = func1
val result: Int = func2(new Swimming(...)) // TYPE ERROR! Since func1 has argument
// of type Tennis.
但是,如果我們做Function1
逆變其參數,所以Function1[Sport,Int] <: Function1[Tennis,Int]
其中Tennis <: Sport
比:
val func1: Function1[Tennis,Int] = ...
val func2: Function1[Sport,Int] = func1 // COMPILE TIME ERROR!
對於相反的情況一切都很好:
個
val func1: Function1[Sport,Int] = ...
val func2: Function1[Tennis,Int] = func1 // OK!
val result1: Int = func1(new Tennis(...)) // OK!
val result2: Int = func2(new Tennis(...)) // OK!
功能必須在其參數類型和協變進行逆變在結果類型:
trait Function1[-T, +U] {
def apply(x: T): U
}
我認爲你的意思是蘋果延伸Fruit而不是Base。 –
@Yuval修復,謝謝。 – dkolmakov