2013-02-10 5 views
17

Es scheint, dass ich etwas wichtiges nicht verstehe, vielleicht über das Löschen (verdammt).Konnte keinen impliziten Wert für den Beweisparameter des Typs scala.reflect.ClassManifest [T] finden

Ich habe eine Methode, die ich Array der Größe schaffen wollte n gefüllt mit Werten von gen:

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

Und es verwendet, wie zum Beispiel:

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

Aber ich Fehler bekommen :

Bitte erklären Sie, was ich falsch gemacht habe, warum dieser Fehler, und welche Art von Code macht es unmöglich?

Antwort

13

Das ist, weil in testArray der konkrete Typ T zur Kompilierzeit nicht bekannt ist. Ihre Signatur muss aussehen wie def testArray[T : ClassManifest](n: Int, gen: =>T), dies fügt einen impliziten Parameter vom Typ ClassManifest[T] zu Ihrer Methode hinzu, der automatisch an den Aufruf von testArray weitergeleitet wird und dann weiter an den Array.fill Aufruf weitergeleitet wird. Dies wird context bound genannt.

+1

In der Tat, das hilft. ClassManifest, wie ich mich leicht erinnere, ist ein Werkzeug, um mit der Art des Löschens umzugehen? Kannst du bitte erklären, wie construct '[T: ClassManifest]' das Problem tatsächlich löst?Geht implizit die Instanz von 'ClassManifest [T]' von wo "T" bekannt ist? – dmitry

+0

Übrigens habe ich noch ein ähnliches Problem :) Innerhalb des 'testArray' nach' Array.fill' versuche ich eine Klasse zu instanziieren, die implizites Ordnen verwendet, deklariert als 'MyClass [T] (seq: Array [T]) (implizites Ord: Ordering [T]) '. Also, auf 'new MyClass (arr)' sehe ich 'Keine implizite Reihenfolge definiert für T'. Irgendeine Chance, ich kann Manifest verwenden, um das zu lösen? Vielleicht die Bestellung mit ClassManifest instanziieren? – dmitry

+1

Um eine Instanz von 'Ordering [A] zu erhalten, fügen Sie einfach hinzu, dass sie als Kontext gebunden ist. 'def testArray [T: Klassenmanifest: Ordnung] (n: Int, gen: => T)'. Wie ich bereits in der Post geschrieben habe, wird der Compiler die impliziten Instanzen durchlaufen, wenn Sie Kontextgrenzen zu Ihren Typparametern hinzufügen. – drexin

4

Die Array.fill Methode hat die folgende Signatur:

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

Um eine Instanz von ClassManifest[T] Sie den konkreten Typ zu wissen brauchen. Ein ClassManifest kann wie folgt erhalten:

implicitly[ClassManifest[String]] 

A ClassManifest für jeden konkreten Typ implizit zur Verfügung steht.

Für implicit Fehler können Sie die implicits Sie mit dem Typ Parameter an die Methode erfordern hinzufügen:

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

Wenn Sie haben sich ClassManifest oder Ordering nicht vorstellen, die Autoren der Bibliothek (am wahrscheinlichsten) hat für Sie sinnvolle Vorgaben gemacht.

Wenn Sie die wrap Methode nennen würde:

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

Wenn Sie Person hier eine benutzerdefinierte Klasse eingeführt, würden Sie einen Fehler für keine implizite Suche:

wrap(2)(3) 

es so erweitert ist Instanz von Ordering[Person]. Die Verfasser der Bibliothek konnten nicht wissen, wie man bestellt Person. Könnte man so wie diese lösen:

class Person 

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

wrap(2)(new Person) 

Die Scala Compiler sucht in verschiedenen Bereichen für implicits, ein Ordering würde in der Regel nicht so festgelegt werden. Ich schlage vor, dass Sie die implizite Auflösung im Internet nachschlagen, um mehr darüber zu erfahren.

Verwandte Themen