2013-04-18 17 views
25

Come posso estrarre i valori di campo da una classe di case in scala utilizzando il nuovo modello di riflessione in scala 2.10? Ad esempio, utilizzando il sottostante non tirare fuori i metodi di campoScala 2.10 riflessione, come estrarre i valori dei campi da una classe di caso

def getMethods[T:TypeTag](t:T) = typeOf[T].members.collect { 
    case m:MethodSymbol => m 
    } 

ho intenzione di loro pompare in

for {field <- fields} { 
    currentMirror.reflect(caseClass).reflectField(field).get 
    } 

risposta

39

MethodSymbol ha un metodo isCaseAccessor che ti permette di fare proprio questo:

Ora è possibile scrivere quanto segue:

scala> case class Person(name: String, age: Int) 
defined class Person 

scala> getMethods[Person] 
res1: List[reflect.runtime.universe.MethodSymbol] = List(value age, value name) 

E ottieni solo i simboli del metodo che desideri.

+0

Ah Mi rendo conto ora che il mio approccio era sbagliato. Qualche idea su come ottenere il casoAccessori da una classe di casi sconosciuta? IE uno che è attualmente memorizzato come val SomeCaseClass: Any –

+0

Wait, no got currentMirror.reflect (someCaseClass) .symbol.asType.typeSignature.members –

+0

Può funzionare con ambiente multi-thread sotto scala 2.10? – jilen

10

Se si desidera ottenere più fantasia è possibile ottenere in ordine controllando il simbolo del costruttore. Questo codice funziona anche se il tipo di classe case in questione ha più costruttori definiti.

import scala.collection.immutable.ListMap 
    import scala.reflect.runtime.universe._ 

    /** 
    * Returns a map from formal parameter names to types, containing one 
    * mapping for each constructor argument. The resulting map (a ListMap) 
    * preserves the order of the primary constructor's parameter list. 
    */ 
    def caseClassParamsOf[T: TypeTag]: ListMap[String, Type] = { 
    val tpe = typeOf[T] 
    val constructorSymbol = tpe.decl(termNames.CONSTRUCTOR) 
    val defaultConstructor = 
     if (constructorSymbol.isMethod) constructorSymbol.asMethod 
     else { 
     val ctors = constructorSymbol.asTerm.alternatives 
     ctors.map(_.asMethod).find(_.isPrimaryConstructor).get 
     } 

    ListMap[String, Type]() ++ defaultConstructor.paramLists.reduceLeft(_ ++ _).map { 
     sym => sym.name.toString -> tpe.member(sym.name).asMethod.returnType 
    } 
    } 
+0

Sto trovando casi in cui questo non riesce con 'scala.ScalaReflectionException: non è un termine' nell'espressione' constructorSymbol.asTerm.alternatives'. Il commento della documentazione per 'declaration' si riferisce a' OverloadedSymbol', ma nessuna entità sembra esistere. –

+0

Si scopre che ciò stava accadendo perché lo chiamavo con 'this.type 'da un tratto usato come supertipo della classe del caso in questione. –

+0

Inoltre, 'case class P (i: Int) (j: Int)'. –

Problemi correlati