Scala 逆变协变

 

协变:在期望接收一个基类集合的地方使用子类实例集合的能力

逆变:在期望接收一个子类集合的地方使用基类实例集合的能力

在默认情况下,scala不允许使用协变和逆变,称之为不变

 

举个例子:我们定义两个class,一个是Pet,一个是Dog,让Dog继承自Pet。


Scala 逆变协变


然后我们调用一个方法,在接Array[Pet]的地方传入Array[Dog]


Scala 逆变协变


在标红处,会提示type mismatch,说明默认情况不支持协变。

但是,我们可以通过特殊的语法来支持协变。

Scala 逆变协变

这里T <: Pet 表示T派生自Pet,Pet为T的上界,传入数组至少得是Array[Pet],或者其子类集合。


反之,也可以支持逆变,在接收子类集合的地方传入基类集合

Scala 逆变协变

这里Dog是T的下界。


前面介绍的,都是在方法参数做的型变。如果我们需要自定义数据格式的话,我们也可以使用”+T”或者“-T”来支持协变和逆变。


举个例子,前面我们定义的pets和dogs。

Scala 逆变协变

如果直接赋值的话,会提示type mismatch。


我们自己定义一个Array,“+T”表示支持协变。

Scala 逆变协变

Scala 逆变协变

petArray期望接收一个MyArray[Pet],但是接收了MyArray[Dog]。


反之,“-T”支持逆变

Scala 逆变协变

Scala 逆变协变

 

完整代码

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.")
  }
}

  

 

上一篇:✍10 pyenv配置及pipenv的使用


下一篇:pyenv 安装与使⽤