[英]Scala accessing members of runtime types using reflection of a class that extends a trait
假设我有一个MyItem
trait 并且它的伴生对象有一个apply()
函数,它创建一个名为SubItem
的类实例,它从MyItem
扩展:
import scala.reflect.runtime.{universe => ru}
trait MyItem {
import MyItem._
def num: Option[Int]
}
object MyItem {
class SubItem(val num: Option[Int]) extends MyItem
def apply(num: Option[Int]): MyItem = new SubItem(num) // creates SubItem
}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
val modifiedItem = MyItem(Some(11))
val theType = getTypeTag(modifiedItem).tpe
如果您打印出上面的theType
,它将是MyItem
。
此时,如果您尝试使用 反射来修改字段num
,它将不起作用,因为MyItem
将num
作为方法,而不是字段(如在MyItem.SubItem
):
val m = ru.runtimeMirror(modifiedItem.getClass.getClassLoader)
val numTermSymb = theType.decl(ru.TermName("num")).asTerm
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectField(numTermSymb) // not going to work
numFieldMirror.get
numFieldMirror.set(Some(999)) // my goal, if possible
不幸的是,上面会抛出scala.ScalaReflectionException: expected a field or an accessor method symbol, you provided method num
。
相反,您应该执行以下操作:
val numTermSymb = theType.decl(ru.TermName("num")).asMethod
val im = m.reflect(modifiedItem)
val numFieldMirror = im.reflectMethod(numTermSymb)
numFieldMirror() // returns `Some(11)`
但我的目标是访问扩展 MyItem 的 SubItem 类并修改其 field 。 如何获取MyItem
类型的实例并修改MyItem
的方法num
正在访问的MyItem.SubItem
中的字段?
代替
val theType = getTypeTag(modifiedItem).tpe
和
val theType = ru.typeOf[MyItem.SubItem]
如果你知道类的名称静态或
val theType = m.staticClass("pckg.MyItem.SubItem").typeSignature
如果您动态知道类的名称。
尝试
val className = modifiedItem.getClass.getName.replace('$', '.')
val theType = m.staticClass(className).typeSignature
实际上, m.staticClass(className).typeSignature
是AnyRef with pckg.MyItem {...}
即子项的父母/ SubItem
theType =:= ru.typeOf[MyItem.SubItem] // false
所以,虽然numFieldMirror.get/set
有效,但最好使用toType
而不是typeSignature
val className = modifiedItem.getClass.getName.replace('$', '.')
val theType = m.staticClass(className).toType
theType =:= ru.typeOf[MyItem.SubItem] // true
另一种方式是纯 Scala 式的
val instanceMirror = m.reflect(modifiedItem)
val theType = instanceMirror.symbol.toType
theType =:= ru.typeOf[MyItem.SubItem] // true
它甚至更好,因为不对字符串使用容易出错和依赖于实现的操作( replace
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.