Как я могу получить Class [T] из неявного ClassTag [T]?

Я хотел бы иметь такой метод, как

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

Внутри этого метода мне нужно вызвать метод Java (вне моего контроля), чтобы создать экземпляр T, для которого требуется Class[T]:

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

Как я могу получить Class[T] от ClassTag[T]? Сначала я думал, что могу использовать runtimeClass из ClassTag, но он имеет тип Class[_], а не Class[T]. Или есть другое неявное значение, которое может автоматически предоставить компилятор, из которого я могу получить Class[T]?

Ответ 1

Вот билет на getClass и связанный обсуждение форума, в котором Одерский размышляет:

Вы также можете использовать трансляцию.

Вот дубликат билета, где getClass исправлено. 5.getClass также выполняет следующие действия:

/** 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]]

Ограничение напоминает этот вопрос о сопоставлении шаблонов с ClassTag, в котором наши наивные ожидания также не выполняются.

Сопротивление Class[A] отражает несоответствие импеданса между типами Scala и платформой?

Учитывая тип класса, все, что действительно можно сделать, это newInstance. Но рефлексивный вызов с зеркалом-конструктором не даст мне моего типа.

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]

Это не выглядит справедливым.

Поскольку этот поток рассылки из 2008 завершается, вы ожидаете использовать меньшее количество бросков в Scala.

Кстати, это не значит, что я не поверил комментариям кода, но:

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

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

[надрез]

 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