协变
假设有类G(或者接口和特征)和类型T1、T2,在T1是T2的子类的情况下如果G< T1>也是G< T2>的子类,那么类G就是协变的。例如:
trait Link[+T]
父类协变,子类也得协变
scala> trait A[+T]
scala> class C[T] extends A[T] // C是invariant的
scala> class X; class Y extends X;
scala> val t:C[X] = new C[Y]
<console>:11: error: type mismatch;
found : C[Y]
required: C[X]
Note: Y <: X, but class C is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
scala> class C[+T] extends A[T]
scala> val t:C[X] = new C[Y]
t: C[X] = C@6a079142
例子:
//在方法prepend中发上了协变,所以Link必须是协变的
class Link[+T](val head: T, val tail: Link[T]) {
//错误的方法:看上去应该没有问题,但是编译错误
//def prepend(newHead: T): Link[T] = new Link(newHead, this)
//正确的方法:在发生协变的方法上必须使用范型限定
def prepend[U >: T](newHead: U): Link[U] = new Link(newHead, this)
}
逆变
假设有类G(或者接口和特征)和类型T1、T2。在T1是T2的子类的情况下如果G< T2>也是G< T1>的子类(与协变是相反的),那么类G就是逆变的。例如:
trait Link[-T]
总结
参数是逆变的或者不变的,返回值是协变的或者不变的。
。。。更新中。。。