好程式設計師大資料學習路線分享Scala系列之泛型
好程式設計師大資料學習路線分享Scala系列之泛型,帶有一個或多個型別引數的類是泛型的。
泛型類的定義:
//
帶有型別引數
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 = {
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]的子型別。
abstract
class Animal {
def name: String
}
case
class Cat(name: String)
extends Animal
case
class Dog(name: String)
extends Animal
Scala標準庫有一個泛型類sealed abstract class List[+A],因為其中的型別引數是協變的,那麼下面的程式呼叫時成功的。
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 PetContainer[P <: Pet](p: P) {
def pet: P = p
}
//Dog
是
Pet
型別的子類
val dogContainer =
new PetContainer[Dog](
new Dog)
//Cat
是
Pet
型別的子類
val catContainer =
new PetContainer[Cat](
new Cat)
//Lion
不是
Pet
型別的子類,編譯通不過
// val lionContainer = new PetContainer[Lion](new Lion)
4. 下界
語法 B >: A 表示引數型別或抽象型別 B 須是型別A的父類。通常,A是類的型別引數,B是方法的型別引數。
上面這段程式碼,因為作為協變型別的B,出現在需要逆變型別的函式引數中,導致編譯不透過。解決這個問題,就需要用到下界的概念。
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)
}
測試
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)
注意:已過時,瞭解即可
視界定義: 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_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)
}
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2659377/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 好程式設計師大資料學習路線分享Scala系列之物件程式設計師大資料物件
- 好程式設計師大資料學習路線分享Scala系列之抽象類程式設計師大資料抽象
- 好程式設計師大資料學習路線分享Scala系列之陣列程式設計師大資料陣列
- 好程式設計師大資料學習路線分享spark之Scala程式設計師大資料Spark
- 好程式設計師大資料學習路線分享Scala系列之對映Map程式設計師大資料
- 好程式設計師大資料學習路線分享Scala系列之基礎篇程式設計師大資料
- 好程式設計師大資料學習路線分享Scala系列之集合操作函式程式設計師大資料函式
- 好程式設計師大資料學習路線分享Scala分支和迴圈程式設計師大資料
- 好程式設計師大資料學習路線分享大資料之字串程式設計師大資料字串
- 好程式設計師大資料學習路線分享MAPREDUCE程式設計師大資料
- 好程式設計師大資料學習路線分享SparkSQl程式設計師大資料SparkSQL
- 好程式設計師大資料教程分享Scala系列之閉包程式設計師大資料
- 好程式設計師大資料分享Scala系列之柯里化程式設計師大資料
- 好程式設計師大資料學習路線分享scala單列和伴生物件程式設計師大資料物件
- 好程式設計師大資料學習路線分享大資料之執行緒程式設計師大資料執行緒
- 好程式設計師大資料學習路線分享Hbase指令學習程式設計師大資料
- 好程式設計師大資料學習路線分享大資料之基礎語法程式設計師大資料
- 好程式設計師大資料教程Scala系列之類程式設計師大資料
- 好程式設計師大資料學習路線分享Map學習筆記程式設計師大資料筆記
- 好程式設計師大資料學習路線分享HDFS學習總結程式設計師大資料
- 好程式設計師大資料學習路線分享hdfs學習乾貨程式設計師大資料
- 好程式設計師大資料學習路線分享Actor學習筆記程式設計師大資料筆記
- 好程式設計師大資料學習路線分享Lambda表示式程式設計師大資料
- 好程式設計師大資料學習路線分享UDF函式程式設計師大資料函式
- 好程式設計師大資料學習路線分享HDFS讀流程程式設計師大資料
- 好程式設計師大資料學習路線分享AWK詳解程式設計師大資料
- 好程式設計師大資料學習路線之mapreduce概述程式設計師大資料
- 好程式設計師Java學習路線分享三大特性之多型程式設計師Java多型
- 好程式設計師大資料培訓分享spark之Scala程式設計師大資料Spark
- 好程式設計師大資料學習路線Hadoop學習乾貨分享程式設計師大資料Hadoop
- 好程式設計師大資料教程Scala系列之繼承程式設計師大資料繼承
- 好程式設計師大資料學習路線分享高階函式程式設計師大資料函式
- 好程式設計師大資料學習路線之zookeeper乾貨程式設計師大資料
- 好程式設計師Java學習路線分享JavaScript基本資料型別分析程式設計師JavaScript資料型別
- 好程式設計師大資料學習路線分享TCP和UDP學習筆記程式設計師大資料TCPUDP筆記
- 好程式設計師大資料學習路線分享Hadoop機架感知程式設計師大資料Hadoop
- 好程式設計師大資料學習路線分享什麼是Hash表程式設計師大資料
- 好程式設計師大資料學習路線分享hive的執行方式程式設計師大資料Hive