一、前言
学过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)
}
}