1. 程式人生 > >Scala 語言學習之泛型(7)

Scala 語言學習之泛型(7)

scala 泛型

==> 泛型類

---> T 可以代表任意類型

class Person[T]{
  private var name:T = _

  def setName(name:T) = {this.name = name}
  def getName():T = {this.name}
}

// ***********測試*****************
object Person{
  def main(args:Array[String]):Unit = {
    var p = new Person[String]()
    p.setName("hello")
    println(p.getName())
  }
}


==> 泛型函數

---> 類型參數放在方法名之後

//* 泛型函數
// 創建一個固定類型的數組
// 普通函數
def mkInt(elems:Int*) = Array[Int](elems:_*)
def mkString(str:String*) = "mkString"

// 使用泛型函數,可以接收任意類型
def mkArray[T:ClassTag](elems:T*) = Array[T](elems:_*)

// ***********測試*****************
// 普通函數只能傳入相對應類型的參數
mkInt(1,2,3)
mkString("hello", "world")

// 泛型函數可以傳入任意類型的參數
mkArray(11.26,665, 84, "hello")


==> 類型的上界和下界(Upper Bounds 和 Lower Bounds)

---> 用來定義泛型變量的範圍 :

---> S <: T (上界) S 必須是 T 類型的子類類本身

class Person1{
  def gender() = {println("gender")}
}

class Man extends Person1{
  override def gender() = {println("man")}
}

class Women extends Person1{
  override def gender() = {println("women")}
object UpperBoundsAndLowerBounds {
  // 定義一個泛型函數,通過上界的方式指定泛型的範圍必須是 Person1 的子類或者Person1 類,並調用類中的 gender 方法
  def getGender[T <: Person1](g:T) = {g.gender()}

  def main(args:Array[String]): Unit = {
    // 創建一個Person1 對象 ,調用getGender 方法調用 Personal 中的 gender 方法
    var p:Person1 = new Person1
    getGender(p)

    // 創建一個 Man 對象 ,通過 getGender 方法調用Man 類中的 gender 方法
    var m = new Man
    getGender(m)
  }

}


---> U >: T(下界) U 必須是 T 類型的父類類本身,此處不作示例,與上面例子類似,只是傳入 getGender 方法中的參數必須是 Person1 類其父類的對象


==> 視圖界定 <%

---> 與類型的上界相似,但是比類型的上界適用範圍更廣,除了所有的子類與類本身,它還允許通過隱式轉換得到的類型

def int2String[T <% String](x:T, y:T) = {
  println(x + "*****" + y)
}

// ***********測試*****************
int2String("hello", "world")
implicit def int2String1(n:Int):String = {n.toString}
int2String(100, 120)


==> 協變和逆變

---> 協變: 泛型變量的值可以是子類類本身 在類型參數前加一個 “+” 符號 轉換為父類

//* 協變和逆變   在類型的前面加入 +號,就可以使類的特征變為協變了
// 將子類對象轉換為父類對象稱為協變 +
// 將父類對象轉換為子類對象稱為逆變 -
package demo1{
  // 父類
  class Animal{}
  // 子類
  class Bird extends Animal
  class Sparrow extends Bird
  
  // 吃東西的類      協變
  class EatSomethings[+T](t:T){}

  // ***********測試*****************
  object Demo1{

    def main(args:Array[String]): Unit={
      // 創建一個吃東西的對象
      var c1:EatSomethings[Sparrow] = new EatSomethings[Sparrow](new Sparrow)

      var c2:EatSomethings[Animal] = c1
    }
  }
}


---> 逆變: 泛型變量的值可以是父類類本身 在類型參數前加一個 “ - ” 符號 父類轉換為子類 例:省略


==> 隱式轉換函數

---> 以關鍵字 implicit 申明

---> 單個參數

class Fruit(name:String){
  def getFruitName():String = {name}
}

class Monkey(f:Fruit){
  def say() = {println("Monkey like " + f.getFruitName()) }
}

// ***********測試*****************
object ImplicitDemo {
  def main(args:Array[String]):Unit = {
    var f:Fruit = new Fruit("bnanan")

    // 調用 fruit 的方法,希望 Monkey這個say 方法來實現
    // 需要將 fruit 的對象轉換為 monkey 對象, 即定義一個隱匿轉換函數
    implicit def fruit2Monkey(f:Fruit):Monkey = {new Monkey(f)}     // 將 fruit 對象轉換為 Monkey 對象
    // 調用Monkey中的 say 方法
    f.say()
  }
}


==> 隱式參數 使用 implicit 關鍵字申明的函數參數

---> 可以使用隱式參數進行類型轉換

// 隱式參數
def testParam(implicit name:String) = {println("The value is " + name)}
implicit val name:String = "這是一個隱式值"

// ***********測試*****************
testParam
//---------------------------------------------------------------

// 帶隱式參數的泛型函數
// Ordered[T] 使類型可排序,
//     原型:def smaller
// (implicit order:T      =>    Ordered[T])
def smaller[T](a:T, b:T)(implicit order:T => Ordered[T]) = if(order(a) < b) a else b

// ***********測試*****************
smaller(100, 56)
smaller("hello", "hi")


==> 隱式類 對類 增加 implicit 限定 的類,其主要作用就是對類的功能增強

---> 編寫一個隱式類,使類實現更多的功能

object testImplicit {

  // 定義一個隱式類
  implicit class Calc(x:Int){
    def add(a:Int):Int = a + x
  }

  // ***********測試*****************
  def main(args:Array[String]):Unit = {
    println("兩個數字的和:" + 1.add(2))
  }
}

---> 程序過程分析:

--- 當 1.add(2)時,scala 的編譯器不會報錯,在當前域中查找,有沒有 implicit 修飾的,同時可以將 Int 作為參數的構造器,並且具有 add 方法的類,通過查找,找到 Calc

--- 利用隱式類 Calc 來執行 add 方法


==> 個人總結:

---> 通過泛型,可以使我們定義一個模具,就像蛋糕的模具,我們可以分別放入草莓,藍莓等不同的原料加工出不同口味的蛋糕來

---> 通過使用 上界,下界,視圖界定,協變,逆變,對泛型的範圍制定規則,使我們可以傳入的符合規則的參數

---> 隱式函數,隱式參數,隱式類,會在程序運行時首先被查找,若有符合 以 implicit 修飾的參數,函數以及類,先執行,然後才運行程序


若總結有誤,還請多多指教,謝謝!!!


Scala 語言學習之泛型(7)