Scala 中的協變,逆變和非變

  協變、逆變、非變介紹
協變和逆變主要是用來解決參數化類型的泛化問題。Scala 的協變與逆變是非常有特色
的,完全解決了Java中泛型的一大缺憾;舉例來說,Java中,如果有 A 是 B 的子類,但 Card[A]
卻不是 Card[B] 的子類;而 Scala 中,只要靈活使用協變與逆變,就可以解決此類 Java 泛
型問題;
由於參數化類型的參數(參數類型)是可變的,當兩個參數化類型的參數是繼承關係(可
泛化),那被參數化的類型是否也可以泛化呢?Java 中這種情況下是不可泛化的,然而 Scala
提供了三個選擇,即協變(“+”)、逆變(“-”)和非變。
下面說一下三種情況的含義,首先假設有參數化特徵 Queue,那它可以有如下三種定義。
(1) trait Queue[T] {}
這是非變情況。這種情況下,當類型 B 是類型 A 的子類型,則 Queue[B]與 Queue[A]沒
有任何從屬關係,這種情況是和 Java 一樣的。
(2) trait Queue[+T] {}
這是協變情況。這種情況下,當類型 B 是類型 A 的子類型,則 Queue[B]也可以認爲是
Queue[A]的子類型,即 Queue[B]可以泛化爲 Queue[A]。也就是被參數化類型的泛化方向與
參數類型的方向是一致的,所以稱爲協變。
(3) trait Queue[-T] {}
這是逆變情況。這種情況下,當類型 B 是類型 A 的子類型,則 Queue[A]反過來可以認
爲是 Queue[B]的子類型。也就是被參數化類型的泛化方向與參數類型的方向是相反的,所
以稱爲逆變。

 C[+T]:如果 A 是 B 的子類,那麼 C[A]是 C[B]的子類。
 C[-T]:如果 A 是 B 的子類,那麼 C[B]是 C[A]的子類。
 C[T]: 無論 A 和 B 是什麼關係,C[A]和 C[B]沒有從屬關係

 

package drt.mavenscala.scala.classdemo

class Super
class Sub extends Super
//協變
class Temp1[+A](title: String)
//逆變
class Temp2[-A](title: String)
//非變
class Temp3[A](title: String)
object Covariance_demo{
  def main(args: Array[String]) {
    //支持協變 Temp1[Sub]還是 Temp1[Super]的子類
    val t1: Temp1[Super] = new Temp1[Sub]("hello scala!!!")
    //支持逆變 Temp1[Super]是 Temp1[Sub]的子類
    val t2: Temp2[Sub] = new Temp2[Super]("hello scala!!!")
    //支持非變 Temp3[Super]與 Temp3[Sub]沒有從屬關係,如下代碼會報錯
    //val t3: Temp3[Sub] = new Temp3[Super]("hello scala!!!")
    //val t4: Temp3[Super] = new Temp3[Sub]("hello scala!!!")
    println(t1.toString)
    println(t2.toString)
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章