一、前言
学过java我们都知道,java中的继承是对类的增强,java中的代理、装饰是对对象方法的增强。而在scala中,隐式转换和隐式参数是Scala中两个非常强大的功能,隐式的对类的方法进行增强,丰富现有类库的功能 。利用隐式转换和隐式参数,你可以提供优雅的类库,对类库的使用者隐匿掉那些枯燥乏味的细节。
而所谓的隐式转化函数,是指那种以implicit关键字声明的带有单个参数的函数。下面,我会通过几个例子来说明scala的隐式转化。
二、小例子
object MyPredef {
//将File变成RichFile
implicit def fileToRichFile(f: File) = new RichFile(f)
}
import MyPredef._
class RichFile(val f: File) {
def read() = Source.fromFile(f).mkString
}
object RichFile {
def main(args: Array[String]) {
val f = new File("c://words.txt")
//装饰 ,显示的增强
//val contents = new RichFile(f).read()
//隐式转化,会到上下文中去找,是不是有一个隐式的上下文 --->MyPredef._
//File类中没有read方法,但是RichFile中有,所有将File变成了RichFile
val contents = f.read()
println(contents)
}
}
三、泛型
[T <: UpperBound] 上界
[T >: LowerBound] 下界
[T <% ViewBound] 视图界定 意味着T可以被隐式转换成M[T]
[T : ContextBound] 上下文界定
[+T] 斜变
[-T] 逆变
[+T] [-T] 一般用于接口中 ,如偏函数中
四、例子
4.1上界
/**
* 指定泛型及上界,传进去的类型(String)必须是Comparable的子类,
* 必须实现Comparable接口,如:Int就不行,因为它没有实现Comparable接口。但我们可以用Integer
* Comparable
* \____________
* String\_____
* \____
*/
class Pair[T <: Comparable[T]] {
def bigger(first: T, second: T): T = {
if(first.compareTo(second) > 0) first else second
}
}
object Pair {
def main(args: Array[String]) {
val p = new Pair[String]
println(p.bigger("spark", "hadoop"))
}
}
4.2下界
定义类, 然后两个对象进行比较
java实现比较的方法,实现Comparable接口:
class Boy(val name: String, var faceValue: Int) extends Comparable[Boy] {
override def compareTo(o: Boy): Int = {
this.faceValue - o.faceValue
}
}
object TestBoy {
def main(args: Array[String]) {
val b1 = new Boy("laoduan", 99)
val b2 = new Boy("laozhao", 999)
val arr = Array[Boy](b1, b2)
//因为我们定义了Boy的比较规则,所以我们可以直接传进去Boy对象就行
val sorted = arr.sortBy(x => x).reverse
for(b <- sorted) {
println(b.name)
}
}
}
scala实现比较的方法有两种,实现Ordered(里面有< 、>、<=等)或者Ordering(里面有compare方法、It方法、gt方法)
class Girl(val name: String, var faceValue: Int) { }
object MyPredef { //另一种new 法:implicit def girl2Ordered(g: Girl) = new Ordered[Girl]{ // implicit val girl2Ordered = (g: Girl) => new Ordered[Girl] { // override def compare(that: Girl): Int = { // g.faceValue - that.faceValue // } // } trait girl2Ordering extends Ordering[Girl] { override def compare(x: Girl, y: Girl): Int = { x.faceValue - y.faceValue } } implicit object Girl extends girl2Ordering }
//视图界定 //view bound 他必须传进去一个隐式转换的函数(函数中包括比较类的类型), // 没有对Girl进行侵入,也就是说比较规则没有跟Boy耦合到一起,如java实现comparable接口进耦合了 //class Chooser[T <% Ordered[T]] { // // def choose(first: T, second: T) : T = { // if(first > second) first else second // } //} //上下文界定 //他必须传进去一个隐式转换的值(函数也是值) class Chooser[T : Ordering] { def choose(first: T, second: T) : T = { val ord = implicitly[Ordering[T]]//隐式参数,转化成了Ordering,Ordering上有gt方法 if(ord.gt(first, second)) first else second } } object Chooser { def main(args: Array[String]) { import MyPredef._ val c = new Chooser[Girl] val g1 = new Girl("anglebaby", 90) val g2 = new Girl("hatano", 99) val g = c.choose(g1, g2) println(g.name) } }
五、例子class Girl(val name: String, val faceValue: Int, val size: Int) { }
object MyPreDef { //输入是Girl类型,输出时Ordered类型, // implicit def girlToOrdered(girl: Girl) = new Ordered[Girl]{ implicit val girlToOrdered = (girl: Girl) => new Ordered[Girl]{ override def compare(that: Girl): Int = { if(girl.faceValue == that.faceValue) { that.size - girl.size } else { girl.faceValue - that.faceValue } } } // implicit object girlOrdering extends [Girl]{ implicit val girlOrdering = new Ordering[Girl] { override def compare(x: Girl, y: Girl): Int = { if(x.faceValue == y.faceValue) { x.size - y.size } else { x.faceValue - y.faceValue } } } }
class MissRight[T] { //相当于ViewBound,利用了柯里化,传的是函数(implicit ord : T => Ordered[T]),可以不传,会到上下文中找类型一样的(输入是T,返回是Ordered[T]) def choose(first: T, second: T)(implicit ord : T => Ordered[T]): T = { if(first > second) first else second } //相当于ContextBound,利用了柯里化,传的是变量(找的是输入【传入参数】是Ordering[T]) def select(first: T, second: T)(implicit ord : Ordering[T]): T ={ if(ord.gt(first, second)) first else second } //第二个括号是传的是隐式值,但我还想用 > def random(first: T, second: T)(implicit ord : Ordering[T]): T ={ //把Ordering转化成Ordered import Ordered.orderingToOrdered if(first > second) first else second } } object MissRight { def main(args: Array[String]) { val mr = new MissRight[Girl] val g1 = new Girl("hatanaoYui", 98, 28) val g2 = new Girl("sora", 98, 33) // import MyPreDef._ //val g = mr.choose(g1, g2) val g = mr.select(g1, g2) println(g.name) } }