如何解决Scala使用扩展特征的类的反射来访问运行时类型的成员
假设我有一个MyItem
特征,并且它的伴随对象有一个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
。
在这一点上,如果您尝试使用reflection来修改字段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类并修改其字段。如何获取类型MyItem
的实例并修改MyItem.SubItem
的方法MyItem
正在访问的num
中的字段?
解决方法
替换
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
)使用易于出错且依赖于实现的操作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。