大數(shù)據(jù)學(xué)習(xí)路線分享Scala系列之泛型,帶有一個(gè)或多個(gè)類(lèi)型參數(shù)的類(lèi)是泛型的。 泛型類(lèi)的定義: //帶有類(lèi)型參數(shù)A的類(lèi)定義 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 } } 泛型類(lèi)的使用,用具體的類(lèi)型代替類(lèi)型參數(shù)A。 val stack = new Stack[Int] stack.push(1) stack.push(2) println(stack.pop) // prints 2 println(stack.pop) // prints 1 1.協(xié)變定義一個(gè)類(lèi)型List[+A],如果A是協(xié)變的,意思是:對(duì)類(lèi)型A和B,A是B的子類(lèi)型,那么List[A]是List[B]的子類(lèi)型。 abstract class Animal { def name: String } case class Cat(name: String) extends Animal case class Dog(name: String) extends Animal Scala標(biāo)準(zhǔn)庫(kù)有一個(gè)泛型類(lèi)sealed abstract class List[+A],因?yàn)槠渲械念?lèi)型參數(shù)是協(xié)變的,那么下面的程序調(diào)用時(shí)成功的。 object CovarianceTest extends App { //定義參數(shù)類(lèi)型List[Animal] def printAnimalNames(animals: List[Animal]): Unit = { animals.foreach { animal => println(animal.name) } }
val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom")) val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex")) //傳入?yún)?shù)類(lèi)型為List[Cat] printAnimalNames(cats) // Whiskers // Tom //傳入?yún)?shù)類(lèi)型為List[Dog] printAnimalNames(dogs) // Fido // Rex } 2.逆變定義一個(gè)類(lèi)型Writer[-A],如果A是逆變的,意思是:對(duì)類(lèi)型A和B,A是B的子類(lèi)型,那么Writer[B]是Writer[A]的子類(lèi)型。 abstract class Animal { def name: String } case class Cat(name: String) extends Animal case class Dog(name: String) extends Animal 定義對(duì)應(yīng)上述類(lèi)進(jìn)行操作的打印信息類(lèi) abstract class Printer[-A] { def print(value: A): Unit } class AnimalPrinter extends Printer[Animal] { def print(animal: Animal): Unit = println("The animal's name is: " + animal.name) }
class CatPrinter extends Printer[Cat] { def print(cat: Cat): Unit = println("The cat's name is: " + cat.name) } 逆變的測(cè)試 object ContravarianceTest extends App { val myCat: Cat = Cat("Boots")
//定義參數(shù)類(lèi)型為Printer[Cat] def printMyCat(printer: Printer[Cat]): Unit = { printer.print(myCat) }
val catPrinter: Printer[Cat] = new CatPrinter val animalPrinter: Printer[Animal] = new AnimalPrinter
printMyCat(catPrinter) //可以傳入?yún)?shù)類(lèi)型為Printer[Animal] printMyCat(animalPrinter) } 3.上界上界定義: T <: A ,表示類(lèi)型變量T 必須是 類(lèi)型A 子類(lèi) abstract class Animal { def name: String }
abstract class Pet extends Animal {}
class Cat extends Pet { override def name: String = "Cat" }
class Dog extends Pet { override def name: String = "Dog" }
class Lion extends Animal { override def name: String = "Lion" } //參數(shù)類(lèi)型須是Pet類(lèi)型的子類(lèi) class PetContainer[P <: Pet](p: P) { def pet: P = p } //Dog是Pet類(lèi)型的子類(lèi) val dogContainer = new PetContainer[Dog](new Dog) //Cat是Pet類(lèi)型的子類(lèi) val catContainer = new PetContainer[Cat](new Cat) //Lion不是Pet類(lèi)型的子類(lèi),編譯通不過(guò) // val lionContainer = new PetContainer[Lion](new Lion) 4.下界語(yǔ)法 B >: A 表示參數(shù)類(lèi)型或抽象類(lèi)型 B 須是類(lèi)型A的父類(lèi)。通常,A是類(lèi)的類(lèi)型參數(shù),B是方法的類(lèi)型參數(shù)。
上面這段代碼,因?yàn)樽鳛閰f(xié)變類(lèi)型的B,出現(xiàn)在需要逆變類(lèi)型的函數(shù)參數(shù)中,導(dǎo)致編譯不通過(guò)。解決這個(gè)問(wèn)題,就需要用到下界的概念。 trait Node[+B] { def prepend[U >: B](elem: U): Node[U] }
case class ListNode[+B](h: B, t: Node[B]) extends Node[B] { def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this) def head: B = h def tail: Node[B] = t }
case class Nil[+B]() extends Node[B] { def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this) } 測(cè)試 trait Bird case class AfricanSwallow() extends Bird case class EuropeanSwallow() extends Bird
val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil()) val birdList: Node[Bird] = africanSwallowList birdList.prepend(new EuropeanSwallow) 5 視界(view bounds)注意:已過(guò)時(shí),了解即可 視界定義: A <% B ,表示類(lèi)型變量A 必須是 類(lèi)型B`的子類(lèi),或者A能夠隱式轉(zhuǎn)換到B class Pair_Int[T <% Comparable[T]] (val first: T, val second: T){ def bigger = if(first.compareTo(second) > 0) first else second }
class Pair_Better[T <% Ordered[T]](val first: T, val second: T){ def smaller = if(first < second) first else second } object View_Bound {
def main(args: Array[String]) { // 因?yàn)?/span>Pair[String] 是Comparable[T]的子類(lèi)型, 所以String有compareTo方法 val pair = new Pair_Int("Spark", "Hadoop"); println(pair.bigger)
/** * Scala語(yǔ)言里 Int類(lèi)型沒(méi)有實(shí)現(xiàn)Comparable; * 那么該如何解決這個(gè)問(wèn)題那; * 在scala里 RichInt實(shí)現(xiàn)了Comparable, 如果我們把int轉(zhuǎn)換為RichInt類(lèi)型就可以這樣實(shí)例化了. * 在scala里 <% 就起這個(gè)作用, 需要修改Pair里的 <: 為<% 把T類(lèi)型隱身轉(zhuǎn)換為Comparable[Int] * String可以被轉(zhuǎn)換為RichString. 而RichString是Ordered[String] 的子類(lèi). */ val pair_int = new Pair_Int(3 ,45) println(pair_int.bigger)
val pair_better = new Pair_Better(39 ,5) println(pair_better.smaller)
}
} 6 上下文界定(context bounds)上下文界定的形式為 T : M, 其中M 必須為泛型類(lèi), 必須存在一個(gè)M[T]的隱式值. class Pair_Context[T : Ordering](val first: T, val second: T){ def smaller(implicit ord: Ordering[T]) = if(ord.compare(first, second) < 0) first else second }
object Context_Bound {
def main(args: Array[String]) {
val pair = new Pair_Context("Spark", "Hadoop") println(pair.smaller)
val int = new Pair_Context(3, 5) println(int.smaller)
}
}
|