鍍金池/ 教程/ Scala/ 當(dāng)有多個隱含轉(zhuǎn)換可以選擇時
轉(zhuǎn)換被方法調(diào)用的對象
View 限定
概述
當(dāng)有多個隱含轉(zhuǎn)換可以選擇時
隱含參數(shù)(二)
隱含參數(shù)(一)
使用 implicits 的一些規(guī)則
隱含類型轉(zhuǎn)換

當(dāng)有多個隱含轉(zhuǎn)換可以選擇時

有時在當(dāng)前作用域可能存在多個符合條件的隱含轉(zhuǎn)換,在大多數(shù)情況下,Scala 編譯器在此種情況下拒絕自動插入轉(zhuǎn)換代碼。隱含轉(zhuǎn)換只有在轉(zhuǎn)換非常明顯的情況下工作良好,編譯器只要例行公事插入所需轉(zhuǎn)換代碼即可。如果當(dāng)前作用域存在多個可選項,編譯器不知道優(yōu)先選擇哪一個使用。

scala> def printLength(seq:Seq[Int]) = println (seq.length)
printLength: (seq: Seq[Int])Unit
scala> implicit def intToRange(i:Int) = 1 to i
intToRange: (i: Int)scala.collection.immutable.Range.Inclusive
scala> implicit def intToDigits(i:Int) = i.toString.toList.map( _.toInt)
intToDigits: (i: Int)List[Int]
scala> printLength(12)
<console>:11: error: type mismatch;
 found   : Int(12)
 required: Seq[Int]
Note that implicit conversions are not applicable because they are ambiguous:
 both method intToRange of type (i: Int)scala.collection.immutable.Range.Inclusive
 and method intToDigits of type (i: Int)List[Int]
 are possible conversion functions from Int(12) to Seq[Int]
              printLength(12)

這個例子產(chǎn)生的歧義是非常明顯的,將一個整數(shù)轉(zhuǎn)換成一組數(shù)字和轉(zhuǎn)換成一個序列是明顯兩個不同的變化。此時應(yīng)該明確指明使用那個變換:

scala> intToDigits(12)
res1: List[Int] = List(49, 50)
scala> printLength(intToDigits(12))
2
scala> printLength(intToRange(12))
12

在 Scala2.7 以前,Scala 編譯器碰到多個可選項時都這么處理,從 2.8 版本以后,這個規(guī)則不再這么嚴格,如果當(dāng)前作用域內(nèi)有多個可選項, Scala 編譯器優(yōu)先選擇類型更加明確的隱含轉(zhuǎn)換。 比如兩個隱含變換一個參數(shù)類型為 String,而另外一個類型為 Any。兩個隱含轉(zhuǎn)換都可以備選項時,Scala 編譯器優(yōu)先選擇參數(shù)類型為 String 的那個隱含轉(zhuǎn)換。

“更明確”的一個判斷規(guī)則如下:

  • 參數(shù)的類型是另外一個類型的子類型
  • 如果兩個轉(zhuǎn)換都是對象的方法,前對象是派生于另外一個對象。

Scala 做出這個改進的原因是為了更好的實現(xiàn) Java,Scala 集合類型(也包括字符串)之間的互操作性。