Scala中的泛型


  1. 類型參數可以用在類、接口和方法中,分別被稱為泛型類、泛型接口、泛型方法  
  2. 類型參數
    1. 調用時不指定[T]:可以通過給泛型聲明的變量傳遞值來讓scala自動推斷泛型的實際類型;返回的是使表達式編譯通過的合適的類型;在編譯時不會檢查類型是否滿足
    2. 調用時指定[T]:可以在函數的調用時候指定泛型的類型;則返回對就必須是T類型;會在編譯時檢查類型,不滿足泛型規則編譯不通過

泛型類

  1. 泛型類:指可以接受類型參數的類。泛型類在集合類中被廣泛使用。(如:各種容器類List、Set、Map)
  2. 定義一個泛型類:泛型類使用方括號 [] 來接受類型參數。一個慣例是使用字母 A 作為參數標識符,當然你可以使用任何參數名稱。
  3. 泛型類的使用  :要使用一個泛型類,將一個具體類型放到方括號中來代替 A。
object test{
  class Stack[A] {
    private var elements: List[A] = Nil
    def push(x: A) { elements = x :: elements }
    def peek: A = elements.head
    def pop(): A = {
      val currentTop = peek
      elements = elements.tail
      currentTop
    }
  }
  // Stack 類的實現中接受類型參數 A。 這表示其內部的列表,var elements: List[A] = Nil,只能夠存儲類型 A 的元素。
  //方法 def push 只接受類型 A 的實例對象作為參數
  def main(args: Array[String]): Unit = {
    val stack = new Stack[Int]
    stack.push(1)
    stack.push(2)
    println(stack.pop)  // prints 2
    println(stack.pop)  // prints 1
  }
}

泛型函數

  1. 泛型函數:指可以接受類型參數的函數
  2. 定義泛型函數:泛型函數使用方括號 [] 來接受類型參數。一個慣例是使用字母 A 作為泛型參數標識符
  3. 泛型類的使用  :要使用一個泛型函數,將一個具體類型放到方括號中來代替 A
object test2{
  def main(args: Array[String]): Unit = {
    def getfiled[T](content: T) = {
      content match {
        case a:Int =>println("這是Int類型")
        case a:String =>println("這是Stringt類型")
        case _ =>println("這是未知類型")
      }
    }
    getfiled("2")       //通過給泛型聲明的變量傳遞值來讓scala自動推斷泛型的實際類型。
  }
}

上邊界

  1. 為什么需要邊界:在指定泛型類型的時候,有時,我們需要對泛型的類型的范圍進行界定,而不是任意的類型
  2. 上邊界:[A<B]
  3. 上邊界特性:左邊的類型參數A是右邊類型B的子類
  4. 作用:我們可能要求某個泛型,它就必須是某個類A的子類,這樣在程序中就可以放心地調用A類的方法
    1. 比如:我們並不知道類型T到底有沒有compareTo方法,編譯報錯,所以要使用上邊界,是參數類型T的類型是含有compareTo的類或者其子類
    2. 編譯報錯:class Pair[T](val first:T, val second:T) {def smaller = if (first.compareTo(second)) }   
    3. 編譯正確:class Pair[T <: Comparable[T]](val first:T, val second:T) {def smaller = if (first.compareTo(second)) }  
object test3{
  class Person(val name: String){}
  class Teacher(name:String)
  class Student(name: String) extends Person(name)
  class Play[T <: Person](p: T) {}


  def main(args: Array[String]): Unit = {
    val wiki=new  Student("Wiki")
    val tom=new Teacher("Tom")
    val play =new Play(wiki) //[Person]可以省略自行推導
    //   val s=new Play(tom) 報錯 因為Teacher不是Person子類。這就是上邊界
  }
}

下邊界 

  1. 下邊界:[A>B]
  2. 下邊界特性:左邊的類型參數A是右邊類型B父類
  3. 注意:如果是在調用的時候省略了[T],讓scala自動去推斷,scala會自動向上轉型,使編譯通過而不會報錯(無論參數是什么類型都會編譯通過)
object test4{
  class Father(val name: String)
  class Child(name: String) extends Father(name)
  class Grandson(name: String) extends Child(name)
  class Frind(val name: String)
  class makyFrind[R >: Child](name:R)
  def main(args: Array[String]): Unit = {
    val father=new Father("wiki")
    val child=new Child("wiki")
    val grandson =new Grandson("wiki")
    val frind =new Frind("wiki")
    val makefrind1: makyFrind[Father] = new makyFrind(father)
    val makefrind2: makyFrind[Child] = new makyFrind(child)
    val makefrind3: makyFrind[Object] = new makyFrind(frind)   //不會報錯 會自動向上轉型
    val makefrind = new makyFrind[Frind](frind) // 編譯報錯   frind不是child的父類
    val makefrind4: makyFrind[Child] = new makyFrind(grandson)
  }
}

視圖邊界

  1. 視圖邊界:[A <% B]
  2. 視圖邊界特性:左邊的類型參數A是右邊類型B或者是其子類。如果不是,左邊類型會使用隱士轉換將左邊的類型參數A轉換為右邊類型B或者其子類(前提是隱式轉換的方法已經具備)
object test5{
  class Person( val name: String)
  class Student(name: String) extends Person(name)
  class worker(val name: String)
  class playBall[T <% Person](p1: T, p2: T)  {
    println("這是playBall對象")
  } //<%必須為這個類或子類,不是就隱式轉換

  implicit def worker2person(obj: Object): Person = {
    obj match {
      case work :worker=>println(work.name+":OK");new Person(work.name)
      case _ =>println("不進行轉換");null
    }
  }
  def main(args: Array[String]): Unit = {
    val  work1=new worker("work1")
    val  work2=new worker("work2")
    val  person=new Person("person")
    val  student=new Student("student")
    val playball3  =new playBall[Person](work1,work2)
    println("=============")
    val playball4: playBall[Person] =new playBall[Person](person,work2)

    // 在調用的時候加上[T],則返回對就必須是T類型,不加[T],返回的是使表達式編譯通過的合適的類型
    //加[T]會在編譯時檢查類型,不滿足泛型規則編譯不通過
    //不加[T]會在編譯時不會檢查類型是否滿足,滿足泛型規則在運行時檢查會報錯
    val play3: playBall[worker] =new playBall(work1,work2)
    val play4: playBall[Object] =new playBall(person,work2)
  }
}

上下文界定 

  1. 上下文界定:[A:B]
  2. 一個上下文界定相當於一個隱式參數。([A:B]:就相當於一個隱式參數implicit b:B[A])
  3. 如:def foo[A : B](a: A) = g(a) 等價於 def foo[A](a:A)(implicit b:B[A]) = g(a)
    1. 隱式參數的類型是B
    2. foo函數的泛型和隱式參數b的泛型是A
  4. implicitly:用來獲取上下文中滿足類型要求的隱式值
object test6{
  class  Stringer[T] {
    def toString(a: T, b: T): Unit = {
      println(s"$a + $b")
    }
  }
  def foo1[T](a: T, b: T)(implicit stringer: Stringer[T])= {
    stringer.toString(a, b)
  }
  // 在方法入參上拿不到關於 Stringer 對象的值,那么我們可以通過 implicitly 這個 標識符 來獲取程序上下文中存在的關於Stringer[T]類型的隱式值,
  // 這個 標識符 的作用就在於此,它是自動的去獲取到。
  def foo2[T:Stringer](a: T, b: T) = {
    val stringer: Stringer[T] = implicitly[Stringer[T]]
    stringer.toString(a, b)
  }
  def main(args: Array[String]): Unit = {
    implicit val stringer: Stringer[Int] = new Stringer[Int]
    val result1 = foo1(2, 3)
    val result2 = foo2(2, 3)
  }
}

Manifest上下文界定 

  1. Manifest上下文界定:[T: Manifest]
  2. 泛型類實例化為一個對象:class Play[T]
    1. 將泛型變成具體的類型;val play1 = new Play[Int]
    2. 將實例化表達式放入[T: Manifest]定義的類或者方法中 :def Pay [T:Manifest] = {val play1 = new Play[T]}
object test7{
  class Meat(val name: String)
  class Vegetable(val name: String)
  def main(args: Array[String]): Unit = {
    val arr1 = new Array[Int](1)  // 傳入具體的類型 
//    val arr2 = new Array[T](1)  //錯誤
    def test[T:Manifest]: Unit ={
      val arr3 = new Array[T](1)  //需要泛型數組所在類或者函數定義[T: Manifest]泛型類型
    }
  }
}

協變和逆變

協變

  1. 協變:對於泛型類ClassName[+T] ,如果A是B的子類,那么ClassName[A]是ClassName[B]的子類(泛型類的的關系和類型參數的關系相同)
/**
  * 如果Father是Son父類,則Person[Father]也是Person[Son]父類,這就是協變
  * []里繼承關系:Grandson->Son->Father
  * Person的繼承關系Person[Grandson]->Person[Son]->Person[Father]
  */
object test81{
  class Father
  class Son extends Father
  class Grandson extends Son
  class Person[+T] (val name: String) //+T協變
  def main(args: Array[String]): Unit = {
    def makeMoney(person:Person[Son]) {
      println(s"你是${person.name},你應該去工作賺錢")
    }
    val father = new Person[Father]("father")
    val son = new Person[Son]("兒子")
    val grandson = new Person[Grandson]("孫子")
//    makeMoney(father) //  父親老了不需要賺錢
      makeMoney(son)
      makeMoney(grandson)
  }
}

逆變

  1. 逆變:對於泛型類ClassName[-T] ,如果A是B的子類,那么ClassName[A]是ClassName[B]的父類(泛型類的的關系和類型參數的關系相反)
/**
  * 逆變是Person將[]里面的繼承關系逆轉過來
  * []里繼承關系:Grandson->Son->Father
  * Person的繼承關系:Person[Grandson]<-Person[Son]<-Person[Father]
  */

object test81{
  class Father
  class Son extends Father
  class Grandson extends Son
  class Person[-T] (val name: String) //-T逆變
  def main(args: Array[String]): Unit = {
    def makeMoney(person:Person[Son]) {
      println(s"你是${person.name},你應該去工作賺錢")
    }
    val father = new Person[Father]("father")
    val son = new Person[Son]("兒子")
    val grandson = new Person[Grandson]("孫子")
    makeMoney(father)
    makeMoney(son)
//  makeMoney(grandson)  //  孫子還小,不需要賺錢
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM