1. 程式人生 > 其它 >Scala 逆變協變

Scala 逆變協變

協變:在期望接收一個基類集合的地方使用子類例項集合的能力

逆變:在期望接收一個子類集合的地方使用基類例項集合的能力

在預設情況下,scala不允許使用協變和逆變,稱之為不變

舉個例子:我們定義兩個class,一個是Pet,一個是Dog,讓Dog繼承自Pet。



然後我們呼叫一個方法,在接Array[Pet]的地方傳入Array[Dog]



在標紅處,會提示type mismatch,說明預設情況不支援協變。

但是,我們可以通過特殊的語法來支援協變。

這裡T <: Pet 表示T派生自Pet,Pet為T的上界,傳入陣列至少得是Array[Pet],或者其子類集合。


反之,也可以支援逆變,在接收子類集合的地方傳入基類集合

這裡Dog是T的下界。


前面介紹的,都是在方法引數做的型變。如果我們需要自定義資料格式的話,我們也可以使用”+T”或者“-T”來支援協變和逆變。


舉個例子,前面我們定義的pets和dogs。

如果直接賦值的話,會提示type mismatch。


我們自己定義一個Array,“+T”表示支援協變。

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


反之,“-T”支援逆變

完整程式碼

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