2014-03-31 57 views
5

讓我們來考慮下面的代碼:爲什麼我們必須從伴隨對象顯式導入隱含參數的隱式轉換?奇怪。

class A 
object A{ 
    implicit def A2Int(implicit a:A)=1 
    implicit def A2String(a:A)="Hello" 
} 

object Run extends App{ 
    implicit val a: A =new A 

    import A.A2Int 
    // without this import this code does not compile, why ? 
    // why is no import needed for A2String then ? 

    def iWantInt(implicit i:Int)=println(i) 
    def iWantString(implicit s:String)=println(s) 

    iWantInt 
    iWantString(a) 
} 

它運行並打印:

1 
Hello 

現在,如果我們註釋掉

import A.A2Int 

那麼我們得到一個編譯錯誤:

enter image description here

隨着線條註釋掉,爲什麼Scala找不到A.A2String如果它能找到A.A2Int

如何解決這個問題?

感謝您的閱讀。

回答

3

不同之處在於,當您執行iWantString(a)時,編譯器會得到一些起點:您正在顯式傳遞編譯器知道的a類型爲A。 鑑於iWantStringString而不是A,編譯器將搜索從AString的隱式轉換,以便插入它並使調用成功。 隱式查找規則聲明編譯器必須在A類的伴隨對象中查找(在其他位置),因爲類型A是轉換的源類型。 這是它發現隱式轉換的地方A2String。 你必須從中得到的結果是,它僅僅是因爲你傳遞了一個編譯器知道的A實例來尋找A的伴隨對象的隱式轉換。

當你只是做iWantInt,編譯器沒有理由再爲A,所以它不會找到你的方法A2Int(和範圍沒有其他的方法/值提供Int類型的隱含價值,編譯失敗,那麼)。

有關隱式查找規則的詳細信息,請參閱 請參閱​​(第7.2章)中的scala規範。這裏是最相關的摘錄:

The implicit scope of a type T consists of all companion modules (§5.4) of classes that are associated with the implicit parameter’s type.

+2

另外,編譯器不會爲了匹配類型執行多個隱*查找*,而你必須爲'iWantInt'隱含查找:一個隱含的查找改造'A'到'Int'和一個隱式查找來查找'iWantInt'的參數。在'iWantString'的情況下,只有一個隱式查找,即將'A'轉換爲'String'。 –

+1

這是不正確的。你有沒有注意到代碼只是用額外的導入語句編譯? 編譯器本身不會執行多個隱式查找**,這是真的。但是在這裏,第一次轉換需要一個「A」類型的隱式值,然後踢第二個隱式查找。 –

+0

你說得對,我的意思是爲了找到隱式的'Int'參數(沒有導入),編譯器必須首先找到從'A'到'Int'的隱式轉換。這些是這兩個隱式查找之間的依賴關係,因爲如果不解決第二個問題,則無法解決第一個問題。你所描述的兩個隱式查找不依賴於另一個。它首先解析了'Int'隱式參數(因爲'A.A2Int'已經被導入),然後解析了第二個隱式查找,也就是'A.A2Int'的隱式參數,由於'val a'是​​隱含的。 –