2013-02-10 31 views
17

看來我不明白某件重要的事情,也許關於擦除(該死的)。無法找到類型scala.reflect.ClassManifest的證據參數的隱式值[T]

我有一個方法,我想從gen創建填入值大小n的數組:

def testArray[T](n: Int, gen: =>T) { 
    val arr = Array.fill(n)(gen) 
    ... 
} 

而且使用它,例如:

testArray(10, util.Random.nextInt(10)) 

,但我得到的錯誤:

scala: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T] 
val arr = Array.fill(n)(gen) 
        ^

請解釋我做錯了什麼,爲什麼這個錯誤,以及它使得什麼樣的代碼變得不可能?

回答

13

這是因爲在testArray中編譯時不知道具體類型T。您的簽名必須看起來像def testArray[T : ClassManifest](n: Int, gen: =>T),這會爲您的方法添加一個類型爲ClassManifest[T]的隱式參數,該參數會自動傳遞給testArray調用,然後再傳遞給Array.fill調用。這被稱爲context bound

+1

事實上,這有幫助。我稍微記得ClassManifest是處理類型擦除的工具嗎?可能,請你解釋一下如何構建'[T:ClassManifest]'實際上解決了這個問題?從「T」已知的地方繞過'ClassManifest [T]'的實例嗎? – dmitry 2013-02-10 10:34:47

+0

順便說一句,我有一個更類似的問題:)在'Array.fill'之後'testArray'我嘗試實例化使用隱式Ordering的類,聲明爲MyClass [T](seq:Array [T]) (隱式ord:Ordering [T])'。因此,在'new MyClass(arr)'我看到'沒有爲T定義的隱式排序'。任何機會我可以使用清單來解決這個問題?也許使用ClassManifest實例化排序? – dmitry 2013-02-10 10:56:25

+1

爲了得到一個'Ordering [A]'的實例,簡單的添加就像上下文綁定一樣。 'def testArray [T:ClassManifest:Ordering](n:Int,gen:=> T)'。正如我在文章中已經寫過的那樣,編譯器會在向類型參數添加上下文邊界時通過隱式實例。 – drexin 2013-02-10 11:11:25

4

Array.fill方法具有以下特徵:

def fill[T](n: Int)(elem: => T)(implicit arg0: ClassManifest[T]): Array[T] 

爲了得到你需要知道具體類型的ClassManifest[T]一個實例。一個ClassManifest可以這樣獲得的:

implicitly[ClassManifest[String]] 

一個ClassManifest隱含適用於每一個具體類型。

對於任何implicit錯誤,您可以您所需要的implicits添加到類型參數的方法:

def wrap[T](n:Int)(elem: => T)(implicit c:ClassManifest[T], o:Ordering[T]) 

如果沒有自我介紹ClassManifestOrdering,圖書館的作家們(最有可能的)爲您提供了合理的默認值。

如果你想調用wrap方法:

wrap(2)(3) 

它擴大這樣的:

wrap[Int](2)(3)(implicitly[ClassManifest[Int]], implicitly[Ordering[Int]]) 

如果你推出一個自定義類Person在這裏,你會得到一個錯誤沒有找到一個隱含的Ordering[Person]的實例。圖書館的作者不可能知道如何訂購Person。你可以解決這樣的:

class Person 

implicit val o = new Ordering[Person] { // implement required methods } 

wrap(2)(new Person) 

Scala編譯器看起來在implicits不同的範圍,一個Ordering通常不會是這樣規定的。我建議你在互聯網上查找隱式解決方案以瞭解更多信息。

相關問題