上篇的例子
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ù)體部分有機(jī)會(huì)使用 implicit 卻沒(méi)有使用。要注意的是當(dāng)年在參數(shù)中使用 implicit 類型時(shí),編譯器不僅僅在需要時(shí)補(bǔ)充隱含參數(shù),而且編譯器也會(huì)把這個(gè)隱含參數(shù)作為一個(gè)當(dāng)前作用域內(nèi)可以使用的隱含變量使用,因此在使用隱含參數(shù)的函數(shù)體內(nèi)可以省略掉 implicit 的調(diào)用而由編譯器自動(dòng)補(bǔ)上。
因此代碼可以簡(jiǎn)化為:
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)類型不匹配,編譯器不會(huì)馬上停止編譯,相反,它會(huì)檢查是否有合適的隱含轉(zhuǎn)換來(lái)修補(bǔ)代碼,在本例中,它發(fā)現(xiàn) orderer 可用。因此編譯器自動(dòng)改寫為 orderer(x)> maxRest。同理我們?cè)谶f歸調(diào)用 maxList 省掉了第二個(gè)隱含參數(shù),編譯器也會(huì)自動(dòng)補(bǔ)上。 同時(shí)我們發(fā)現(xiàn),maxList 代碼定義了隱含參數(shù) orderer,而在函數(shù)體中沒(méi)有地方直接引用到該參數(shù),因此你可以任意改名 orderer,比如下面幾個(gè)函數(shù)定義是等價(jià)的:
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 中專門定義了一種簡(jiǎn)化的寫法– 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 限定,也就是說(shuō),我可以使用任意類型的 T,只要它可以看成類型 Ordered[T]。這和 T 是 Orderer[T]的子類不同,它不需要 T 和 Orderer[T]之間存在繼承關(guān)系。 而如果類型 T 正好也是一個(gè) Ordered[T]類型,你也可以直接把 List[T]傳給 maxList,此時(shí)編譯器使用一個(gè)恒等隱含變換:
implicit def identity[A](x:A): A =x
在這種情況下,該變換不做任何處理,直接返回傳入的對(duì)象。