深圳大数据学习: 泛型–【千锋】
带有一个或多个类型参数的类是泛型的。
泛型类的定义:
// 带有类型参数 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
8.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
}
8.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)
}
8.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)
8.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)
8.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)
}
}
8.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 )
}
}