Scala 【 13 類型參數 】

類型參數

​ Scala 的類型參數其實意思與 Java 的泛型是一樣的,也是定義一種類型參數,比如在集合,在類,在函數中,定義類型參數,然後就可以保證使用到該類型參數的地方,就肯定,也只能是這種類型。從而實現程序更好的健壯性。

泛型類

​ 泛型類其實就是在類的聲明中,定義一些泛型類型,然後在類內部,比如 field 或者 method,就可以使用這些泛型類型。

​ 使用泛型類,通常是需要對類中的某些成員,比如某些 field 和 method 中的參數或變量,進行統一的類型限制,這樣可以保證程序更好的健壯性和穩定性。

​ 如果不使用泛型進行統一的類型限制,那麼在後期程序運行過程中,難免會出現問題,比如傳入了不希望的類型,導致程序出問題。

​ 在使用類的時候,比如創建類的對象,將類型參數替換爲實際的類型,即可。

​ Scala 自動推斷泛型類型特性:直接給使用了泛型類型的 field 賦值時, Scala 會自動進行類型推斷。

// 每個學生來自不同的地方,id可能是Int,可能是String

class Student[T](val localId:T){
    def getSchool(bornId:T) = "S-" + bornId + "-" + localId
}

val Li = new Student[Int](100)

泛型函數

​ 泛型函數,與泛型類類似,可以給某個函數在聲明時指定泛型類型,然後在函數體內,多個變量或者返回值之間,就可以使用泛型類型進行聲明,從而對某個特殊的變量,或者多個變量,進行強制性的類型限制。

​ 與泛型類一樣,你可以通過給使用了泛型類型的變量傳遞值來讓 Scala 自動推斷泛型的實際類型,也可以在調用函數時,手動指定泛型類型。

// 卡片售賣機,可以指定卡片的內容,內容可以是String類型或Int類型

def getCard[T](content:T) = {
    if(content.isInstanceOf[Int]) "card:001," + content
    else if(content.isInstanceOf[String]) "card:002," + content
    else "card: " + content
}

getCard[String]("hello card")
上邊界Bounds

​ 在指定泛型類型的時候,有時,我們需要對泛型類型的範圍進行界定,而不是可以是任意的類型。

​ 比如,我們可能要求某個泛型類型,它就必須是某個類的子類,這樣在程序中就可以放心地調用泛型類型繼承的父類的方法,程序才能正常的使用和運行。此時就可以使用上下邊界 Bounds 的特性。

​ Scala的上下邊界特性允許泛型類型必須是某個類的子類,或者必須是某個類的父類。

class Person(val name:String){
    def sayHello = println("Hello, I'm " + name)
    def makeFriends(p:Person){
        sayHello
        p.sayHello
    }
}

class Student(name:String) extends Person(name)

class Party[T <: Person](p1:T, p2:T){
    def play = p1.makeFriends(p2)
}

// 測試
val p1 = new Student("Li")
val p2 = new Student("Chy")
val pa = new Party[Student](p1,p2)
pa.play
下邊界 Bounds

​ 除了指定泛型類型的上邊界,還可以指定下邊界,即指定泛型類型必須是某個類的父類。

class Father(val name:String)

class Child(name:String) extends Father(name)

def getIDCard[R >: Child](person:R){
    if(person.getClass == classOf[Child]) println("please tell us your parent's name")
    else if(person.getClass == classOf[Father]) println("sign your name for your child's ID card.")
    else println("Error.")
}

val father = new Father("Li")
val child = new Child("Lhy")

getIDCard[Father](father)
getIDCard[Child](child)
View Bounds

​ 上下邊界 Bounds,雖然可以讓一種泛型類型,支持有父子關係的多種類型。但是,在某個類與上下邊界 Bounds 指定的父子類型範圍內的類都沒有任何關係,則默認是肯定不能接受的。

​ 然而,View Bounds 作爲一種上下邊界 Bounds 的加強版,支持可以對類型進行隱式轉換,將指定的類型進行隱式轉換後,再判斷是否在邊界指定的類型範圍內。

class Person(val name:String){
	def sayHello = println("Hello, I'm " + name)
    def makeFriends(p:Person){
        sayHello
        p.sayHello
    }
}

class Student(name:String) extends Person(name)

class Dog(val name:String) {
    def sayHello = println("Wank, I'm " + name)
}

// 隱式轉換
implicit def dog2person(obj:Object):Person = if(obj.isInstanceOf[Dog]){
    val _dog = obj.asInstanceOf[Dog];
    new Person(_dog.name)} else Nil


class Party[T <% Person](p1:T,p2:T)

val stu = new Student("Li")
val dog = new Dog("WangCai")
val pa = new Party(stu,dog)
Context Bounds

​ Context Bounds 是一種特殊的Bounds,它會根據泛型類型的聲明,比如“T: 類型”要求必須存在一個類型爲“類型[T]”的隱式值。

class Calculator[T: Ordering] (val number1: T, val number2: T) {
  def max(implicit order: Ordering[T]) = if(order.compare(number1, number2) > 0) number1 else number2
}
Manifest Context Bounds

​ 在 Scala 中,如果要實例化一個泛型數組,就必須使用 Manifest Context Bounds 。也就是說,如果數組元素類型爲 T 的話,需要爲類或者函數定義 [T: Manifest] 泛型類型,這樣才能實例化 Array[T] 這種泛型數組。

class Meat(val name:String)
class Vegetable(val name:String)

def packageFood[T:Manifest](food:T*) = {
    val foodPackage = new Array[T](food.length)
    for(i <- 0 until food.length) foodPackage(i) = food(i)
    foodPackage
}
Existential Type

​ 在 Scala 裏,有一種特殊的類型參數,就是 Existential Type ,存在性類型。

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