我的代码深入探讨了案例类的构造函数字段,当然这些字段本身可能很复杂(事物列表,映射,选项和其他案例类)。我发现在运行时提取字段值的代码在最高级字段上工作得很好,但在我尝试访问更深的字段时会爆炸。示例如下。
我现实生活中我的应用程序会反省每个级别的字段,所以我知道'stuff'是另一个案例类(我有符号/类型),我知道Dos'字段符号/类型。但这是在运行时获得的,所以我认为它正在爆炸,因为它不知道[T] / Manifest [T]。有没有办法通过反射在运行时获得它?我的代码怎么会改变?我发现的例子似乎都需要各种各样的东西[T],我不会为'dos'做,对吗?
case class Uno( name:String, age:Int, pets:List[String], stuff:Dos )
case class Dos( foo:String )
object Boom extends App {
val ru = scala.reflect.runtime.universe
val m = ru.runtimeMirror(getClass.getClassLoader)
val u = Uno("Marcus",19,List("fish","bird"),Dos("wow"))
println("NAME: "+unpack(u,"name")) // Works
println("PETS: "+unpack(u,"pets")) // Works
// ----- Goes Boom -------
val dos = unpack(u,"stuff")
println("Other: "+unpack(dos,"foo")) // Boom!
// -----------------------
// Get object value for named parameter of target
def unpack[T]( target:T, name:String )(implicit man:Manifest[T]) : Any = {
val im = m.reflect(target)
val fieldX = ru.typeOf[T].declaration(ru.newTermName(name)).asTerm.accessed.asTerm
im.reflectField(fieldX).get
}
}
答案 0 :(得分:3)
您完全正确,dos
的类型为Any
。
FieldMirror.symbol.typeSignature是你从typeOf [Dos]获得的。
因此,请考虑从unpack中返回一对(Any,Type)以将某些内容传递给unpack(目标,类型,名称)。有点像:
case class Uno(name: String, age: Int, pets: List[String], stuff: Dos)
case class Dos(foo: String)
object Boom extends App {
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{ currentMirror => cm }
import scala.reflect.ClassTag
val u = Uno("Marcus", 19, List("fish", "bird"), Dos("wow"))
println("NAME: " + unpack(u, "name")) // Works
println("PETS: " + unpack(u, "pets")) // Works
// ----- Goes Boom -------
val (dos, dosT) = unpack(u, "stuff")
println("Other: " + unpack(dos, dosT, "foo")) // Boom! ...or fizzle
// -----------------------
def unpack[T: TypeTag](target: T, name: String): (Any, Type) = unpack(target, typeOf[T], name)
// Get object value for named parameter of target
def unpack[T](target: T, t: Type, name: String): (Any, Type) = {
val im = cm.reflect(target)(ClassTag(target.getClass))
val fieldX = t.declaration(newTermName(name)).asTerm.accessed.asTerm
val fm = im.reflectField(fieldX)
(fm.get, fm.symbol.typeSignature)
}
}