让我们来看看你提到的第一个例子。 考虑,我们有:
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