Подтвердить что ты не робот

Можно ли преобразовать TypeTag в манифест?

В нашей библиотеке используются TypeTags, но теперь нам нужно взаимодействовать с другой библиотекой, которая требует Manifests. Есть ли простой способ создания манифеста из TypeTag?

4b9b3361

Ответ 1

gourlaysama anwer использует Class [_], поэтому аргументы типа стираются. Я придумал реализацию, которая сохраняет аргументы типа здесь: Как сохранить параметр типа во время преобразования TypeTag в Manifest?

Здесь код:

  def toManifest[T:TypeTag]: Manifest[T] = {
    val t = typeTag[T]
    val mirror = t.mirror
    def toManifestRec(t: Type): Manifest[_] = {
      val clazz = ClassTag[T](mirror.runtimeClass(t)).runtimeClass
      if (t.typeArgs.length == 1) {
        val arg = toManifestRec(t.typeArgs.head)
        ManifestFactory.classType(clazz, arg)
      } else if (t.typeArgs.length > 1) {
        val args = t.typeArgs.map(x => toManifestRec(x))
        ManifestFactory.classType(clazz, args.head, args.tail: _*)
      } else {
        ManifestFactory.classType(clazz)
      }
    }
    toManifestRec(t.tpe).asInstanceOf[Manifest[T]]
  }

Ответ 2

Если вы попытаетесь наивно вызвать Manifest, когда присутствует TypeTag, компилятор даст вам подсказку относительно решения:

import reflect.runtime.universe._
import reflect.ClassTag

def test[A : TypeTag] = manifest[A]

error: to create a manifest here, it is necessary to interoperate with the type
tag `evidence$1` in scope.
however typetag -> manifest conversion requires a class tag for the corresponding
type to be present.
to proceed add a class tag to the type `A` (e.g. by introducing a context bound)
and recompile.
   def test[A : TypeTag] = manifest[A]
                                   ^

Итак, если у вас есть ClassTag в области видимости, компилятор сможет создать необходимый Manifest. У вас есть два варианта:

  • Добавить второй контекст, связанный всюду TypeTag, как в:

    def test[A : TypeTag : ClassTag] = manifest[A] // this compiles
    
  • Или сначала преобразуйте TypeTag в ClassTag, затем попросите Manifest:

    def test[A](implicit ev: TypeTag[A]) = {
      // typeTag to classTag
      implicit val cl = ClassTag[A]( ev.mirror.runtimeClass( ev.tpe ) )
    
      // with an implicit classTag in scope, you can get a manifest
      manifest[A]
    }