2014-02-15 34 views
6

的設置在這個例子中(斯卡拉2.10.3):爲什麼不適用的隱式轉換會引入歧義?

trait S[A] 
trait T[A] 
implicit class X[A : S](a: A) { def foo() { } } 
implicit class Y[A : T](a: A) { def foo() { } } 
implicit object I extends S[String] 

這編譯:

new X("").foo() 

這不:

new Y("").foo() 

因爲沒有隱含T[String]

could not find implicit value for evidence parameter of type T[String] 
       new Y("").foo() 
      ^

因此,我認爲scalac能準確無誤地應用來自String隱式轉換爲X

"".foo() 

但是相反,我們得到:

type mismatch; 
found : String("") 
required: ?{def foo: ?} 
Note that implicit conversions are not applicable because they are ambiguous: 
both method X of type [A](a: A)(implicit evidence$1: S[A])X[A] 
and method Y of type [A](a: A)(implicit evidence$1: T[A])Y[A] 
are possible conversion functions from String("") to ?{def foo: ?} 
       "".foo() 
      ^

這是故意的嗎?當scalac列舉候選人時,不應該考慮每次轉換是否真的有效?

回答

4

我的非學術觀點是,隱式的設計並不意味着每次看起來都應該工作。我認爲這是一個好主意,否則你很容易陷入一種隱含的地獄。您可以通過添加更多隱式轉換層來擴展您的示例。通過查看代碼很難判斷哪個函數實際被調用。有明確的規則,但我記得簡單地說,如果從代碼中不明顯發生什麼事情,它是行不通的。

我要說的是,你的代碼打破One-at-a-time Rule導致破Non-Ambiguity RuleA : S只是一個語法糖,並且可以改寫爲:

implicit class X[A](a: A)(implicit e: S[A]) { def foo() { } } 
implicit class Y[A](a: A)(implicit e: T[A]) { def foo() { } } 

沒有「第二」隱電平(方法參數e)的分辨率兩類XY看起來是一樣的編譯器,因此是不明確的。正如鏈接文檔所說:「出於理智考慮,編譯器在已經處於嘗試另一隱式中間時不會插入其他隱式轉換。」

+0

我可以抽象地購買該解釋,但我不遵循在細節上。一次一個表示隱式轉換不構成,這不會在這裏發生,否則'new X(「」)。foo()'不會編譯。非模糊性是關於「沒有其他*可能*轉換插入」的具體內容。 –

+0

我同意你的看法,並很樂意看到更具體的答案。無論如何,這個問題很好 –

相關問題