Scala學習整理[第十九章 泛型和約束系統]

第十九章 泛型和約束系統

這章是scala的重點和難點 ,建議多找一點資料和範例理解 ,scala很多庫函數都使用了這種語法 ,瞭解後才能更好的閱讀源碼 .

package SecondWithProgrammingInScala

import java.util.Comparator

/**
  * scala的泛型和約束[類型系統]
  * 書上的例子比較散 ,所以參考了其他資料來了解scala這個最強大的特性
  */

//1.泛型 (類似Java)
class Reference[T] {
  private var contents: T = _

  def set(value: T) {
    contents = value
  }

  def get: T = contents
}

object ReferenceApp {
  def main(args: Array[String]) {
    val cell = new Reference[Int]
    cell.set(13)
    println("Reference contains the half of " + (cell.get * 2))

    val cell2 = new Reference[String]
    cell2.set("33")
    println("Reference contains the number " + cell2.get)
  }
}

//2.類型變量界定 : 劃定一個類型的範圍
//類似java中 List<? extends Object> list = new ArrayList<String>(); ,限制類型
// <:泛型類型限定符,Comparable[T]是類型T的上界,T是Comparable[T]的下界
class Pair[T <: Comparable[T]](val first: T, val second: T) {
  //表示T必須是Comparable的子類 ,可以使用compareTo方法進行比較,如果大於0返回first
  def bigger = if (first.compareTo(second) > 0) first else second
}

class PairLowerBound[T](val first: T, val second: T) {
  // 傳入的參數泛型T必須爲 R的子類 ,返回構造Pair_Lower_Bound對象 ,R是T的上界,T是R的下界
  // new了一個父類型
  def replaceFirst[R >: T](newFirst: R) = new PairLowerBound[R](newFirst, second)
}

object TypeVariableBoundsApp {
  def main(args: Array[String]): Unit = {
    val pair = new Pair("Spark", "Hadoop")
    println(pair.bigger)

    val pairLowerBound = new PairLowerBound("Int", 12)
    println(pairLowerBound.first.getClass)
    println(pairLowerBound.replaceFirst('I').first.getClass)
  }
}

//3.視圖界定 : 自動的隱式轉換
//視圖界定(Views Bounds) ,其符號爲 T <% S,關係和上界類似
//如果類型T不是Ordered[T]的子類 ,會進行隱式轉換成Ordered的子類 ,再使用這個方法
class ViewBounds[T <% Ordered[T]](val first: T, val second: T) {
  def compare = if (first > second) 1 else 0
}

class ViewBounds2[T](val first: T, val second: T)(implicit ord: T => Ordered[T]) {
  def compare = if (ord(first) > second) 1 else 0
}


object ViewBoundsApp {
  def main(args: Array[String]): Unit = {
    //Int(沒有Ordered方法)->RichInt
    val c = new ViewBounds[Int](2, 1)
    println(c.compare)
  }
}

//4.上下文界定 : 爲隱式參數引入的語法糖 ,使隱式轉換簡潔
object ContextBound {
  //隱式參數的做法
  def max1[T](a: T, b: T)(implicit cp: Comparator[T]) = {
    if (cp.compare(a, b) >= 0) a else b
  }

  //使用上下文界定 : 將參數列表中的隱式轉換移到內部
  def max2[T: Comparator](a: T, b: T) = {
    //def inner(implicit c: Comparator[T]) = c.compare(a, b)
    //if (inner > 0) a else b
    val cp = implicitly[Comparator[T]]
    if (cp.compare(a, b) > 0) a else b
  }

  def main(args: Array[String]): Unit = {
    implicit val c = new Comparator[Int] {
      override def compare(a: Int, b: Int) = a - b
    }

    println(max1(5, 6))
    println(max2(5, 6))
  }
}


//5.組合界定符
/*
  表示:A和B爲T上界
  T <: A with B
  表示 : A和B爲T下界
  T >: A with B
  表示 : 同時擁有上界和下界 , 並且A爲下界 , B爲上界 , A爲B的子類 , 順序不能顛倒 。
  T >: A <: B
  表示 : 類型變量界定 , 即同時滿足AT這種隱式值和BT這種隱式值
  T: A: B
  表示 : 視圖界定 , 即同時能夠滿足隱式轉換的A和隱式轉換的B
  T <% A <% B
*/


//6.泛型關鍵字
//Java中的泛型是編譯時的 ,編譯後會對泛型繼續擦除
//List<String>,List<Int>到了JVM中都是List類型 ,只是會對他加上String,Int的強制轉換
//因此如果運行時需要判斷類型 ,就要對類型參數進行保存
object KeyWord {
  /**
    * scala在2.10裏用TypeTag替代了Manifest,用ClassTag替代了ClassManifest
    * 因爲Manifest在路徑依賴系統中有問題
    * 例如 類A{類B}
    * 類B的類型會隨着類A的不同實例而不同
    * 然而Manifest判斷是相同的
    */
  //ClassTag : 把原始類型T保存在方法上下文
  //數組必須明確具體類型 ,但只有在函數運行時纔會知道類型 ,這時候泛型已經被擦除了
  import scala.reflect.ClassTag

  def mkArray1[T: ClassTag](elems: T*) = Array[T](elems: _*)

  //TypeTag不僅包含類的類別信息,還包含了所有靜態的類信息
  //在沒有路徑歧義的地方 ,使用Manifest也可以 ,官方建議替換
  import scala.reflect.runtime.universe._

  def matchType[T](x: List[T])(implicit tag: TypeTag[T]) = {
    if (typeOf[T] =:= typeOf[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

  def main(args: Array[String]): Unit = {
    mkArray1(1, 2).foreach(println)
    matchType(List("1"))
    matchType(List(1))

    //7.類型約束
    // A =:=B // 表示A類型等同於B類型
    // A <:<B   // 表示A類型是B類型的子類
    def rocky[T](i: T)(implicit ev: T <:< java.lang.String) {
      println("Life is short ,you need spark!!!")
    }
    //rocky(1) 無法運行
    rocky("Spark")
  }
}


//8.協變和逆變
/**
  * covariant協變 : C[+T]:如果A是B的子類,那麼C[A]是C[B]的子類。
  * contravariance逆變 : C[-T]:如果A是B的子類,那麼C[B]是C[A]的子類。
  * Invariance不變(默認) : 只能使用原始類型 . C[T]:無論A和B是什麼關係,C[A]和C[B]沒有從屬關係。
  */
//父類
class Person

//子類
class Student extends Person

//協變父類
class C[+T](val args: T)

//協變子類 繼承協變類型
class S[+T](args: T) extends C[T](args)

object CovariantApp {
  def main(args: Array[String]): Unit = {
    //創建泛型爲Student類的類C
    val child = new S[Student](new Student)
    //因爲開啓了協變 ,S[Person]是S[Student]的父類
    val parent: S[Person] = child
    //同樣C是S的父類 ,C[Person]也是S[Student]的父類
    val parent1: C[Person] = child
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章