上篇的例子
def maxListImpParam[T](element:List[T])
(implicit orderer:T => Ordered[T]):T =
element match {
case List() =>
throw new IllegalArgumentException("empty list!")
case List(x) => x
case x::rest =>
val maxRest=maxListImpParam(rest)(orderer)
if(orderer(x) > maxRest) x
else maxRest
}
其中函數(shù)體部分有機會使用 implicit 卻沒有使用。要注意的是當年在參數(shù)中使用 implicit 類型時,編譯器不僅僅在需要時補充隱含參數(shù),而且編譯器也會把這個隱含參數(shù)作為一個當前作用域內(nèi)可以使用的隱含變量使用,因此在使用隱含參數(shù)的函數(shù)體內(nèi)可以省略掉 implicit 的調(diào)用而由編譯器自動補上。
因此代碼可以簡化為:
def maxList[T](element:List[T])
(implicit orderer:T => Ordered[T]):T =
element match {
case List() =>
throw new IllegalArgumentException("empty list!")
case List(x) => x
case x::rest =>
val maxRest=maxList(rest)
if(x > maxRest) x
else maxRest
}
編譯在看到 x > maxRest 發(fā)現(xiàn)類型不匹配,編譯器不會馬上停止編譯,相反,它會檢查是否有合適的隱含轉(zhuǎn)換來修補代碼,在本例中,它發(fā)現(xiàn) orderer 可用。因此編譯器自動改寫為 orderer(x)> maxRest。同理我們在遞歸調(diào)用 maxList 省掉了第二個隱含參數(shù),編譯器也會自動補上。 同時我們發(fā)現(xiàn),maxList 代碼定義了隱含參數(shù) orderer,而在函數(shù)體中沒有地方直接引用到該參數(shù),因此你可以任意改名 orderer,比如下面幾個函數(shù)定義是等價的:
def maxList[T](element:List[T])
(implicit orderer:T => Ordered[T]):T =
...
def maxList[T](element:List[T])
(implicit iceCream:T => Ordered[T]):T =
...
由于在 Scala 這種用法非常普遍,Scala 中專門定義了一種簡化的寫法– View 限定。如下:
def maxList[T <% Ordered[T]](element:List[T]) :T =
element match {
case List() =>
throw new IllegalArgumentException("empty list!")
case List(x) => x
case x::rest =>
val maxRest=maxList(rest)
if(x > maxRest) x
else maxRest
}
其中 <% 為 View 限定,也就是說,我可以使用任意類型的 T,只要它可以看成類型 Ordered[T]。這和 T 是 Orderer[T]的子類不同,它不需要 T 和 Orderer[T]之間存在繼承關(guān)系。 而如果類型 T 正好也是一個 Ordered[T]類型,你也可以直接把 List[T]傳給 maxList,此時編譯器使用一個恒等隱含變換:
implicit def identity[A](x:A): A =x
在這種情況下,該變換不做任何處理,直接返回傳入的對象。