2013-08-04 13 views
11

Chciałbym mieć metodę jakJak mogę uzyskać klasę [T] z niejawnego ClassTag [T]?

def retrieve[T](value: Option[T])(implicit ct: ClassTag[T]): T; 

Wewnątrz tej metody potrzebne do wywołania metody Java (poza moją kontrolą), aby utworzyć wystąpienie T wymagającego Class[T]:

public <T> T construct(clazz: Class<T> /* other arguments */) { ... } 

Jak mogę uzyskać Class[T] od ClassTag[T]? Najpierw pomyślałem, że mogę użyć runtimeClass z ClassTag, ale jego typ to Class[_], a nie Class[T]. Czy istnieje inna wartość domyślna, którą kompilator może automatycznie dostarczyć, z której mogę uzyskać Class[T]?

+6

Nie należy bać odlewania przy użyciu java odbicie. Po prostu wykonaj 'asInstanceOf [Class [T]]'. –

Odpowiedz

14

Here is the ticket na getClass i linked forum discussion w którym Odersky spekuluje:

Można również skorzystać z obsady.

Here is the duplicate ticket gdzie ustalono getClass. 5.getClass rzuca również:

/** Return the class object representing an unboxed value type, 
* e.g. classOf[int], not classOf[java.lang.Integer]. The compiler 
* rewrites expressions like 5.getClass to come here. 
*/ 
def anyValClass[T <: AnyVal : ClassTag](value: T): jClass[T] = 
    classTag[T].runtimeClass.asInstanceOf[jClass[T]] 

Ograniczenie przypomina this question about pattern matching z ClassTag, w którym nasze naiwne oczekiwania nie są również spełnione.

Czy rezystancja względem Class[A] reprezentuje niedopasowanie impedancji między typami Scala i platformą?

Biorąc pod uwagę typ zajęć, wszystko, co naprawdę można zrobić, to newInstance. Ale wywołanie refleksyjne za pomocą lustra konstruktora nie przywróci mi mojego typu.

scala> res24 reflectConstructor res25.asMethod 
res27: reflect.runtime.universe.MethodMirror = constructor mirror for Bar.<init>(): Bar (bound to null) 

scala> res27() 
res28: Any = [email protected] 

scala> bar.getClass.newInstance 
res29: Bar = [email protected] 

scala> classOf[Bar].newInstance 
res30: Bar = [email protected] 

To nie wydaje się sprawiedliwe.

Jak podsumowuje ten wątek z 2008 roku, spodziewasz się użyć mniejszej liczby rzutów w Scali.

BTW, to nie tak, że nie uwierzyli komentarz kodu, ale:

scala> 5.getClass 
res38: Class[Int] = int 

scala> :javap - 
    Size 1285 bytes 
    MD5 checksum a30a28543087238b563fb1983d7d139b 
    Compiled from "<console>" 

[ciach]

9: getstatic  #27     // Field scala/runtime/ScalaRunTime$.MODULE$:Lscala/runtime/ScalaRunTime$; 
12: iconst_5  
13: invokestatic #33     // Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer; 
16: getstatic  #38     // Field scala/reflect/ClassTag$.MODULE$:Lscala/reflect/ClassTag$; 
19: invokevirtual #42     // Method scala/reflect/ClassTag$.Int:()Lscala/reflect/ClassTag; 
22: invokevirtual #46     // Method scala/runtime/ScalaRunTime$.anyValClass:(Ljava/lang/Object;Lscala/reflect/ClassTag;)Ljava/lang/Class; 
25: putfield  #18     // Field res38:Ljava/lang/Class; 
28: return   
+0

To dobre badania, ale nie jest to dobra odpowiedź. Linki, cytaty, kod źródłowy, dezasemblacja ... Jak więc uzyskać "Class [T]" z 'ClassTag [T]'? (Mam na myśli to, że mogę to zrozumieć, ale myślę, że pierwszym priorytetem odpowiedzi powinno być udzielenie odpowiedzi na to pytanie, a dopiero potem zapewnienie kontekstu.) –

+1

@DanielDarabos mówi, że należy użyć rzutowania, a następnie pokazuje przykład używając rzutowania, aby przejść od ClassTag to Class. Ta odpowiedź wykracza daleko poza zakres obowiązków. PO nie miał zdania. –

+0

_ "Użyj rzutu" _ jest cytatem spekulacji z forum. "Przykład" to fragment kodu z wewnętrznych komponentów środowiska wykonawczego Scala ('ScalaRunTime.scala') i jest wstawiany bez słowa" tak to robisz ". Zwraca 'jClass [T]', który jest lokalnym aliasem dla 'Class [T]' w pliku, ale czytelnicy odpowiedzi nie wiedzą o tym. W każdym razie nie chcę krytykować odpowiedzi, chciałem tylko wyrazić opinię. Niezależnie od tego jest to bardzo wnikliwa odpowiedź. –

Powiązane problemy