隱式變換也可以轉換調用方法的對象,比如但編譯器看到X .method,而類型 X 沒有定義 method(包括基類)方法,那么編譯器就查找作用域內定義的從 X 到其它對象的類型轉換,比如 Y,而類型Y定義了 method 方法,編譯器就首先使用隱含類型轉換把 X 轉換成 Y,然后調用 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 重載了兩個+運算,參數類型分別為 Rational 和 Int。因此你可以把 Rational 和 Rational 相加,也可以把 Rational 和整數相加。
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
但是我們如果使用 1+ oneHalf 會出現什么問題呢?
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
^
整數和其相關類型都沒定義和 Rational 類型相加的操作,因此編譯器報錯,此時編譯器在1能夠轉換成 Rational 類型才可以編譯過,因此我們可以定義一個從整數到 Rational 的隱含類型變換:
scala> implicit def int2Rational(x:Int) = new Rational(x)
int2Rational: (x: Int)Rational
現在再執(zhí)行 1+oneHalf
:
scala> 1 + oneHalf
res3: Rational = 3/2
在定義了 int2Rational 之后,編譯器看到 1+oneHalf,發(fā)現 1 沒有定義和 Rational 相加的操作,通常需要報錯,編譯器在報錯之前查找當前作用域從 Int 到其他類型的定義,而這個轉換定義了支持和 Rational 相加的操作,本例發(fā)現 int2Rational,因此編譯器將 1+ oneHalf 轉換為
int2Rational(1)+oneHalf
隱式轉換可以用來擴展 Scala 語言,定義新的語法結構,比如我們在定義一個 Map 對象時可以使用如下語法:
Map(1 -> "One", 2->"Two",3->"Three")
你有沒有想過->內部是如何實現的,->不是 scala 本身的語法,而是類型 ArrowAssoc 的一個方法。這個類型定義在包 Scala.Predef 對象中。 Scala.Predef 自動引入到當前作用域,在這個對象中,同時定義了一個從類型 Any 到 ArrowAssoc 的隱含轉換。因此當使用 1 -> “One”時,編譯器自動插入從 1 轉換到 ArrowAsso c轉換。具體定義可以參考 Scala 源碼。
利用這種特性,你可以定義新的語法結構,比如行業(yè)特定語言(DSL)。