好程序員大數據學習路線分享Scala系列之泛型,帶有一個或多個類型參數的類是泛型的。程序員
泛型類的定義:ide
//帶有類型參數A的類定義
class Stack[A] {
private var elements: List[A] = Nil函數
//泛型方法
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {oop
val currentTop = peek elements = elements.tail currentTop
}
}學習
泛型類的使用,用具體的類型代替類型參數A。測試
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1大數據
1.協變
定義一個類型List[+A],若是A是協變的,意思是:對類型A和B,A是B的子類型,那麼List[A]是List[B]的子類型。this
abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animalspa
Scala標準庫有一個泛型類sealed abstract class List[+A],由於其中的類型參數是協變的,那麼下面的程序調用時成功的。scala
object CovarianceTest extends App {
//定義參數類型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"))
//傳入參數類型爲List[Cat]
printAnimalNames(cats)
// Whiskers
// Tom
//傳入參數類型爲List[Dog]
printAnimalNames(dogs)
// Fido
// Rex
}
2.逆變
定義一個類型Writer[-A],若是A是逆變的,意思是:對類型A和B,A是B的子類型,那麼Writer[B]是Writer[A]的子類型。
abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal
定義對應上述類進行操做的打印信息類
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)
}
逆變的測試
object ContravarianceTest extends App {
val myCat: Cat = Cat("Boots")
//定義參數類型爲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)
//能夠傳入參數類型爲Printer[Animal]
printMyCat(animalPrinter)
}
3.上界
上界定義: T <: A ,表示類型變量T 必須是 類型A 子類
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"
}
//參數類型須是Pet類型的子類
class PetContainerP <: Pet {
def pet: P = p
}
//Dog是Pet類型的子類
val dogContainer = new PetContainerDog
//Cat是Pet類型的子類
val catContainer = new PetContainerCat
//Lion不是Pet類型的子類,編譯通不過
// val lionContainer = new PetContainerLion
4.下界
語法 B >: A 表示參數類型或抽象類型 B 須是類型A的父類。一般,A是類的類型參數,B是方法的類型參數。
上面這段代碼,由於做爲協變類型的B,出如今須要逆變類型的函數參數中,致使編譯不經過。解決這個問題,就須要用到下界的概念。
trait Node[+B] {
def prependU >: B: Node[U]
}
case class ListNode+B extends Node[B] {
def prependU >: B: ListNode[U] = ListNode(elem, this)
def head: B = h
def tail: Node[B] = t
}
case class Nil[+B]() extends Node[B] {
def prependU >: B: ListNode[U] = ListNode(elem, this)
}
測試
trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird
val africanSwallowList= ListNodeAfricanSwallow, Nil())
val birdList: Node[Bird] = africanSwallowList
birdList.prepend(new EuropeanSwallow)
5 視界(view bounds)
注意:已過期,瞭解便可
視界定義: A <% B ,表示類型變量A 必須是 類型B`的子類,或者A可以隱式轉換到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]) {
// 由於Pair[String] 是Comparable[T]的子類型, 因此String有compareTo方法
val pair = new Pair_Int("Spark", "Hadoop"); println(pair.bigger) /** * Scala語言裏 Int類型沒有實現Comparable; * 那麼該如何解決這個問題那; * 在scala裏 RichInt實現了Comparable, 若是咱們把int轉換爲RichInt類型就能夠這樣實例化了. * 在scala裏 <% 就起這個做用, 須要修改Pair裏的 <: 爲<% 把T類型隱身轉換爲Comparable[Int] * String能夠被轉換爲RichString. 而RichString是Ordered[String] 的子類. */ 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 必須爲泛型類, 必須存在一個M[T]的隱式值.
class Pair_ContextT : Ordering{
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)
}
}