1. 程式人生 > >Scala Type Parameters 1

Scala Type Parameters 1

型別引數

  • 表現形式:在名稱後面以方括號表示, Array[T]

  • 何處使用

    • class 中,用於定義變數、入參、返回值

      class Pair[T, S](val first: T, val second: S)
      // scala 可自動推斷具體的型別
      val p = new Pair(42, "String") // Pair[Int, String]
      
    • 函式、方法

      def getMiddle[T](a: Array[T]) = a(a.length / 2)
      
  • 型別邊界

    • 上邊界 T <: UpperBound

      // 比較大小
      class Pair[T](val first: T, val second: T) {
        def smaller = if (first.compareTo(second) < 0) first else second  
      }
      

      無法確定 first 是否存在 compareTo 方法,所以必須新增約束,fist 必須是 Comparable 的子型別,即需要新增上邊界

      class Pair[T <: Comparable[T]](val first: T, val second: T) {
        def smaller = if (first.compareTo(second) < 0) first else second
      }
      
    • 下邊界 T >: LowerBound

      // 替換第一個元素
      class Pair[T](val first: T, val second: T) {
        def replaceFirst(newFirst: T) = new Pair[T](newFirst, second)
      }
      

      替換第一個元素為 T 的父類 R,那麼返回型別是什麼? 如果需要返回 R,則需要新增約束,即需要下邊界;否則返回的型別為 Any

      // 返回型別自動推斷為 new Pair[R]
      def replaceFirst[R >: T](newFirst: R) = new Pair(newFirst, second)
      
    • 上下文邊界 T : ContextBound

      Scala 2.8 對 Array 進行了更新優化,使用隱式轉換和 manifest 將陣列整合為 Scala 的集合庫

      def tabulate[T](len: Int, f: Int => T)(implicitm: ClassManifest[T]) = {
        val xs = new Array[T](len)
        for(i <- 0 until len) xs(i) = f(i)
        xs
      }
      
      // 簡化後
      def tabulate[T: ClassManifest](len: Int, f: Int => T) = {
        val xs = new Array[T](len)
        for(i <- 0 until len) xs(i) = f(i)
        xs
      }
      
      • ClassTag, 指定執行時的型別,如 Array[Int] 在執行時想指定為 int[]

        import scala.reflect._
        def makePair[T : ClassTag](first: T, second: T) = {
          val r = new Array[T](2); r(0) = first; r(1) = second; r
        }
        
        makePair(4, 9)
        
        // 實際呼叫
        makePair(4, 9)(classTag)
        
        // new 操作,即 ClassTag[Int] 構建原始型別陣列 int[2]
        classTag.newArray
        
    • 多個邊界

      • 可同時新增上界和下界 T >: Lower <: Upper
      • 不可新增多個上界或多個下屆,但可實現多個 trait,
        • T <: Comparable[T] with Serializable with Cloneable
      • 可指定多個上下文邊界 T : Ordering : ClassTag
  • 型別約束

    • 測試是否相等 T =:= U
    • 測試是否為子類 T <:< U
    • 測試是否可轉換 T => U

    要新增該約束,需新增隱式引數

    // 約束類
    class Pair[T](val first: T, val second: T)(implicit ev: T <:< Comparable[T])
    
    // 約束方法呼叫,只有型別滿足才能呼叫成功,否則報錯
    class Pair[T](val first: T, val second: T) {
      def smaller(implicit ev: T <:< Ordered[T]) =
        if (first < second) first else second
    }
    
    // 便於型別推斷
    def firstLast[A, C <: Iterable[A]](it: C) = (it.head, it.last)
    // 無法推斷型別 A
    firstLast(List(1, 2, 3)) // [Nothing, List[Int]]
    // 新增約束關係
    def firstLast[A, C](it: C)(implicit ev: C <:< Iterable[A]) = (it.head, it.last)