隱式變換也可以轉(zhuǎn)換調(diào)用方法的對象,比如但編譯器看到X .method,而類型 X 沒有定義 method(包括基類)方法,那么編譯器就查找作用域內(nèi)定義的從 X 到其它對象的類型轉(zhuǎn)換,比如 Y,而類型Y定義了 method 方法,編譯器就首先使用隱含類型轉(zhuǎn)換把 X 轉(zhuǎn)換成 Y,然后調(diào)用 Y 的 method。
下面我們看看這種用法的兩個典型用法:
這里我們使用前面例子 Scala開發(fā)教程(50): Ordered Trait 中定義的 Rational 類型為例:
class Rational (n:Int, d:Int) {
require(d!=0)
private val g =gcd (n.abs,d.abs)
val numer =n/g
val denom =d/g
override def toString = numer + "/" +denom
def +(that:Rational) =
new Rational(
numer * that.denom + that.numer* denom,
denom * that.denom
)
def +(i:Int) :Rational =
new Rational(numer +1*denom,denom)
def * (that:Rational) =
new Rational( numer * that.numer, denom * that.denom)
def this(n:Int) = this(n,1)
private def gcd(a:Int,b:Int):Int =
if(b==0) a else gcd(b, a % b)
}
類 Rational 重載了兩個+運算,參數(shù)類型分別為 Rational 和 Int。因此你可以把 Rational 和 Rational 相加,也可以把 Rational 和整數(shù)相加。
scala> val oneHalf = new Rational(1,2)
oneHalf: Rational = 1/2
scala> oneHalf + oneHalf
res0: Rational = 1/1
scala> oneHalf + 1
res1: Rational = 3/2
但是我們?nèi)绻褂?1+ oneHalf 會出現(xiàn)什么問題呢?
scala> 1 + oneHalf
<console>:10: error: overloaded method value + with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int <and>
(x: String)String
cannot be applied to (Rational)
1 + oneHalf
^
整數(shù)和其相關(guān)類型都沒定義和 Rational 類型相加的操作,因此編譯器報錯,此時編譯器在1能夠轉(zhuǎn)換成 Rational 類型才可以編譯過,因此我們可以定義一個從整數(shù)到 Rational 的隱含類型變換:
scala> implicit def int2Rational(x:Int) = new Rational(x)
int2Rational: (x: Int)Rational
現(xiàn)在再執(zhí)行 1+oneHalf:
scala> 1 + oneHalf
res3: Rational = 3/2
在定義了 int2Rational 之后,編譯器看到 1+oneHalf,發(fā)現(xiàn) 1 沒有定義和 Rational 相加的操作,通常需要報錯,編譯器在報錯之前查找當(dāng)前作用域從 Int 到其他類型的定義,而這個轉(zhuǎn)換定義了支持和 Rational 相加的操作,本例發(fā)現(xiàn) int2Rational,因此編譯器將 1+ oneHalf 轉(zhuǎn)換為
int2Rational(1)+oneHalf
隱式轉(zhuǎn)換可以用來擴展 Scala 語言,定義新的語法結(jié)構(gòu),比如我們在定義一個 Map 對象時可以使用如下語法:
Map(1 -> "One", 2->"Two",3->"Three")
你有沒有想過->內(nèi)部是如何實現(xiàn)的,->不是 scala 本身的語法,而是類型 ArrowAssoc 的一個方法。這個類型定義在包 Scala.Predef 對象中。 Scala.Predef 自動引入到當(dāng)前作用域,在這個對象中,同時定義了一個從類型 Any 到 ArrowAssoc 的隱含轉(zhuǎn)換。因此當(dāng)使用 1 -> “One”時,編譯器自動插入從 1 轉(zhuǎn)換到 ArrowAsso c轉(zhuǎn)換。具體定義可以參考 Scala 源碼。
利用這種特性,你可以定義新的語法結(jié)構(gòu),比如行業(yè)特定語言(DSL)。