例子一:
implicit def stringWrapper(s : String) =
new RandomAccessSeq[Char] {
def length = s.length
def apply(i : Int) = s.charAt(i)
}
这是一个String=>RandomAccessSeq的隐式转换,只要import这个隐式转换,String会被编译器替换为RandomAccessSeq
例子二:
implicit def int2String(x : Int) = x.toString
一个Int=>String的隐式转换,import后,Int会被编译器替换为String
例子三:
implicit def double2Int(x : Double) = x.toInt
一个Double=>Int的隐式转换,import后,Double会被编译器转换为Int
例子四:
implicit def int2Double(x : Int) = x.toDouble
一个Int=>Double的隐式转换,import后,Int会被编译器转换为Double
例子一到例子四的implicit,看上去像是一个宏定义,只不过比宏定义更加的聪明。当编译器碰到了String、Int、Double时,会自动的将它们根据隐式转换的规则进行转换。
例子五:隐式参数
class PreferredDrink(name : String){}
implicit val prompt = new PreferredPrompt("Yes, master")
def greet(name : String)(implicit prompt : PreferredDrink) = {
println("yes")
}
在调用greet时,只需要传入第一个参数即可,因为隐式参数就像是宏定义,取代了greet的第二个参数
例子六:带有隐式参数的函数
def maxList[T](elements : List[T])
(implicit orderer : T => Ordered[T]) : T =
elements match {
case List() =>
throw new IllegalArgumentException("empty list")
case List(x) => x
case x :: rest =>
val maxRest = maxList(rest) //maxList有两个参数的,第二个参数编译器用隐式值补足
if (x > maxRest) x //x不一定有>的方法,如果没有,编译器自动隐式转换为orderer(x)
else maxRest
}
隐式参数orderer,类型是T=>Ordered[T],提供了更多的T类型的信息,类型T由List[T]指明,如果存在T=>Ordered[T]的隐式转换,则是有效的。
orderer是相当关键的参数信息,就是为了说明T具体是什么样的,并不是随便一个类型可以满足T=>Ordered[T]的类型。
如果将implicit用于参数上,编译器不仅将会尝试用隐式值补足参数,还会把这个参数当做可用的隐式操作而用于方法体中。
例子六中的隐式参数使用方法非常的普遍,可以用“视界”来简化maxList:
def maxList[T <% Ordered[T]](elements : List[T]) : T,后面的方法是一样的。
注意,这里是<%(视界),而不是<:(上界),觉得“视界”比“上界”多了一个隐式转换。