Scala学习笔记4——高级编程
-
泛型
- 泛型类
- 泛型函数
class A[T] class B[T,S](val b1 : T, val b2 : S) def print[A](content : A){ println(content) } print[String]("xxx") //res = "xxx"
- 上下界
object Bounds extends App{ vsl p = new Pair("A","B") println(p.smaller) / val s1 = new Student("A") val s2 = new Student("B") new Pair(s1,s2) //Pair[Student,Student] val p1 = new Person("AA") println(pair1.replace(p1)) } //上界 class Pair[T <: Comparable[T]](val first : T, val second : T){ def smaller = if(first.compareTo(second) < 0) first else second } //下界(R是T的超类(父类)) class Pair[T](val first : T, val second : T){ def replace[R >: T](first : R) = new Pair(first,second) } class Person(val name : String) class Student(name : String) extends Person(name)
-
视图界定(view bound)
在Scala中,如果想标记某一个泛型可以隐式的转换为另一个泛型,可以使用:[T <% Comparable[T]]
T <% V : T到V的隐式转换
class Pair3[T <% Comparable[T]](val first: T, val second: T) { def smaller = if (first.compareTo(second) < 0) first else second override def toString = "(" + first + "," + second + ")" } object Main3 extends App { val p = new Pair3(4, 2) println(p.smaller) }
-
上下文界定(context bound)
- 上下文界定的形式为T:M,其中M是另一个泛型类,它要求必须存在一个类型为M[T]的隐式值。
- 下面类定义要求必须存在一个类型为Ordering[T]的隐式值,当你使用了一个使用了隐式值的方法时,传入该隐式参数
class Pair4[T: Ordering](val first: T, val second: T) { def smaller(implicit ord: Ordering[T]) = { println(ord) if (ord.compare(first, second) < 0) first else second } override def toString = "(" + first + "," + second + ")" } object Main4 extends App{ override def main(args: Array[String]): Unit = { val p4 = new Pair4(1, 2) println(p4.smaller) } }
-
Manifest上下文界定
Manifest是Scala 2.8引入的一个特质,用于编译器在运行时也能获取泛型类型的信息。
//m代表T的信息
def test[T] (x:T, m:Manifest[T]) { ... }
//由于上述做法需要用户手动传入m,显得不好。因此采用下述做法,其中隐式参数m是由编译器根据上下文自动传入的。
def foo[T](x: List[T]) (implicit m: Manifest[T])
//可以简化为下式
def foo[T:Manifest] (x: List[T])
-
类型约束
- T=:=U 意思为T类型是否等于U类型
- T<:<U 意思为T类型是否为U或U的子类型
-
T<%U 意思是是否存在T到U的隐式转换
-
型变
对于类型C[T]持有类型参数T;给定两个类型A和B,如果满足A <: B,则C[A]与 C[B]之间存在三种关系:
- 协变: C[A] <: C[B], Scala中使用+标识协变
- 逆变: C[A] :> C[B], Scala中使用-标识逆变
- 否则,C是不变的,不变则没有标识
trait C[+A] // C is covariant trait C[-A] // C is contravariant trait C[A] // C is nonvariant //一般地,“不可变的”类型意味着“型变”,而“可变的”意味着“不变”。 //其中,对于不可变的(Immutable)类型C[T] //如果它是一个生产者,其类型参数应该是协变的,即C[+T]; //如果它是一个消费者,其类型参数应该是逆变的,即C[-T]。
-
隐式转换(implicit)
- 为现有的类库增加功能
object Implicit extends App{ import Context._ //引进隐式转换 或 import Context.file2RichFile new File("xxx").read } class RichFile(val file : File){ def read = Source.fromFile(file.getPath).mkString } object Context{ implicit def file2RichFile(f : file) = new RichFile(f) }
-
隐式转换规则
- 如果代码能在不使用隐式转换的前提下通过编译,则不会使用隐式转换。
- 编译器不会同时使用多个隐式转换
- 不允许存在二义性的隐式转换
-
隐式参数
object AAA{ def print(content : String)(implicit prefix : String){ println(prefix + ":" + content) } } object Demo extends App{ import Context._ AAA.print("Jack") //res = "Hello:Jack",自动赋值 } object Context{ implicit def ccc : String = "Hello" }
-
利用隐式参数进行隐式转换
def smaller[T](a:T,b:T)(implicit order : Ordered[T]) = if (order(a) < b) a else b
-
隐式类
- 必须定义在一个class/object/trait里面
- 构造器中只能带一个不是implicit的参数
- 作用域中不能有与隐式类类名相同的成员变量,函数名,及object名称。
object Demo extends App{ import Context._ println(1.add2) } object Context{ //代表可以为int->HH做隐式转换 implicit class HH(x : Int) = { def add2() = x + 2 } } //Ordering混入Comparator接口。
object Demo extends App{ val l1 = new Line(1) val l2 = new Line(2) val p3 = new Pair2[Line](l1,l2) println(p3.smaller)//报错,缺少隐式的ordering,如何解决? implicit object Line extends LineOrdering//(放在最上边) } class Pair2[T : Ordering](val first : T,val second : T){ //implicity[Ordering[T]]可以获得对应的隐式值 def smaller(implicit ord : ordering[T]) = if (ord.compare(first,second)<0) first else second } //有了这个trait,Ordering[Line]就可以发生隐式转换 trait LineOrdering extends Ordering[Line]{ override def compare(x : Line,y : Line) { if (x.len < y.len) -1 else if(x.len == y.len) 0 else 1 } } class Line(val len : Double){ override def toString() = ":" + len }