Scala 逆变协变
Scala 逆变协变
协变(covariant):在期望接收一个基类集合的地方使用子类实例集合的能力
逆变(cotravariant):在期望接收一个子类集合的地方使用基类实例集合的能力
在默认情况下,scala不允许使用协变和逆变,称之为不变
举个例子:我们定义两个class,一个是Pet,一个是Dog,让Dog继承自Pet。
然后我们调用一个方法,在接Array[Pet]的地方传入Array[Dog]
在标红处,会提示type mismatch,说明默认情况不支持协变。
但是,我们可以通过特殊的语法来支持协变。
这里T <: Pet 表示T派生自Pet,Pet为T的上界,传入数组至少得是Array[Pet],或者其子类集合。
反之,也可以支持逆变,在接收子类集合的地方传入基类集合
这里Dog是T的下界。
前面介绍的,都是在方法参数做的型变(variance)。如果我们需要自定义数据格式的话,我们也可以使用”+T”或者“-T”来支持协变和逆变。
举个例子,前面我们定义的pets和dogs。
如果直接赋值的话,会提示type mismatch。
我们自己定义一个Array,“+T”表示支持协变。
petArray期望接收一个MyArray[Pet],但是接收了MyArray[Dog]。
反之,“-T”支持逆变
如果,在我们定义的数据结构内,我们想再定义协变和逆变。
可以看到,红色的地方表示语法错误:“covariant type T occurs in contravariant position”。
说明方法上的参数“K:>T” 和class上的参数“+T”的T必须是“相反”的。T 在class本是协变的位置,但是在方法上却是在逆变的位置。
完整代码
object test extends App {
def workWithPet(pets:Array[Pet]): Unit ={
}
var dogs = Array[Dog](new Dog("bill"), new Dog("bob"))
// workWithPet(dogs)
def workWithPet2[T <: Pet](pets:Array[T]): Unit ={
}
workWithPet2(dogs)
var pets = Array[Pet](new Pet("bill"), new Pet("bob"))
def workWithPet3[T >: Dog](dogs:Array[T]): Unit ={
}
workWithPet3(pets)
// pets = dogs
// dogs = pets
var dogArray = new MyArray[Dog]()
var petArray = new MyArray[Pet]()
petArray = dogArray
var dogArray2 = new MyArray2[Dog]()
var petArray2 = new MyArray2[Pet]()
dogArray2 = petArray2
}
class MyArray[+T]{
}
class MyArray2[-T]{
}
class Pet(name: String) {
override def toString: String = name
def behavior(): Unit = {
println("This is a Pet.")
}
}
class Dog(name: String) extends Pet(name: String) {
override def toString: String = name
override def behavior(): Unit = {
println("This is a Dog.")
}
}

浙公网安备 33010602011771号