2014-04-30 6 views
10

Unsere Bibliothek verwendet TypeTags, aber jetzt müssen wir mit einer anderen Bibliothek interagieren, die Manifests erfordert. Gibt es eine einfache Möglichkeit, ein Manifest aus einem TypeTag zu erstellen?Kann ein TypeTag in ein Manifest konvertiert werden?

+0

Für Vorerst ein Link, der helfen kann: http: //docs.scala-lang .org/überblicke/reflection/typetags-manifests.html – eruve

Antwort

3

gourlaysamas anwer verwendet Class [_], also ty Die Argumente werden gelöscht. Ich habe mit einer Implementierung kommen, die die Typargumente hier bewahrt: How to maintain type parameter during TypeTag to Manifest conversion?

Hier ist der Code:

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]] 
    } 
9

Wenn Sie naiverweise versuchen, eine Manifest zu rufen, wenn ein TypeTag vorhanden ist, wird der Compiler geben Ihnen einen Hinweis auf die Lösung:

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] 
           ^

Wenn Sie also ein ClassTag haben in Bereich, der Compiler wird in der Lage sein, die notwendigen Manifest zu erstellen. Sie haben zwei Möglichkeiten:

  • einen zweiten Kontext überall gebunden hinzufügen TypeTag ist, wie in:

    def test[A : TypeTag : ClassTag] = manifest[A] // this compiles 
    
  • Oder die TypeTag zu einem ClassTag, dann für eine Manifest fragen konvertieren:

    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] 
    }