2013-02-10 9 views
17

Wygląda na to, że nie rozumiem czegoś ważnego, może o wymazaniu (cholera).Nie można znaleźć wartości domyślnej dla parametru dowodu typu scala.reflect.ClassManifest [T]

Mam metodę, którą chciał stworzyć tablicę wielkości n wypełniona wartościami od gen:

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

i używać go na przykład jako:

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

Ale otrzymuję błąd :

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

Proszę wyjaśnić, co zrobiłem źle, dlaczego ten błąd, i jakiego rodzaju kodu to uniemożliwia?

Odpowiedz

13

To dlatego, że w testArray konkretny typ T nie jest znany podczas kompilacji. Twój podpis musi wyglądać jak def testArray[T : ClassManifest](n: Int, gen: =>T), doda to niejawny parametr typu ClassManifest[T] do twojej metody, który jest automatycznie przekazywany do wywołania testArray, a następnie dalej przekazywany do wywołania Array.fill. Nazywa się to context bound.

+1

Rzeczywiście to pomaga. ClassManifest, ponieważ trochę pamiętam, to narzędzie do radzenia sobie z wymazywaniem typów? Czy możesz wyjaśnić, w jaki sposób konstruowanie '[T: ClassManifest]' faktycznie rozwiązuje problem?Przepuszcza w sposób jawny instancję 'ClassManifest [T]' od miejsca, gdzie znane jest 'T'? – dmitry

+0

Nawiasem mówiąc, mam jeszcze jeden podobny problem :) Wewnątrz 'testArray' po' Array.fill' próbuję utworzyć instancję klasy, która używa ukrytego porządkowania, zadeklarowanego jako 'MyClass [T] (seq: Array [T]) (implicit ord: Ordering [T]) '. Tak więc, w 'nowej MyClass (arr)' widzę 'Brak domyślnego porządku zdefiniowanego dla T'. Czy istnieje szansa, że ​​będę mógł użyć manifestu, aby to rozwiązać? Może utworzyć zamówienie przy użyciu ClassManifest? – dmitry

+1

Aby uzyskać instancję 'Ordering [A]' po prostu dodaj jako kontekst związany. 'def testArray [T: ClassManifest: Ordering] (n: Int, gen: => T)'. Jak już napisałem w poście, kompilator przejdzie przez niejawne instancje, gdy dodasz granice kontekstu do parametrów twojego typu. – drexin

4

Sposób Array.fill ma następujący podpis:

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

W celu uzyskania instancję ClassManifest[T] trzeba znać konkretny typ. ClassManifest można uzyskać tak:

implicitly[ClassManifest[String]] 

ClassManifest jest domyślnie dostępne dla każdego rodzaju betonu.

Dla każdego błędu implicit można dodać implicits można wymagać metody z parametrem typu:

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

Jeżeli nie udało się wprowadzić ClassManifest lub Ordering, autorzy biblioteki mają (najprawdopodobniej) pod warunkiem rozsądne domyślne dla Ciebie.

Jeśli chcesz wywołać metodę wrap:

wrap(2)(3) 

jest rozwinięty tak:

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

Jeśli wprowadzono niestandardowej klasy Person tutaj, to pojawi się błąd o nie znalezieniu niejawna instancja: Ordering[Person]. Autorzy biblioteki nie mogli wiedzieć, jak zamówić Person. Można rozwiązać to tak:

class Person 

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

wrap(2)(new Person) 

Kompilator Scala wygląda w różnych zakresach dla implicits An Ordering zazwyczaj nie być określony w taki sposób. Proponuję wyszukanie ukrytej rozdzielczości w Internecie, aby dowiedzieć się więcej na ten temat.

Powiązane problemy