如何使用Scala反射递归访问对象的所有公共成员?
发布时间:2020-12-16 18:14:51 所属栏目:安全 来源:网络整理
导读:我不知道如何在不知道/指定其类型的情况下如何访问对象成员RECURSIVELY.在我的情况下,问题仅限于我想访问的惰性val和对象成员.对象可以嵌套到任何深度,其中存在惰性val.例如: object TestShallow { lazy val value1 = 1}object TestDeep { lazy val value1
我不知道如何在不知道/指定其类型的情况下如何访问对象成员RECURSIVELY.在我的情况下,问题仅限于我想访问的惰性val和对象成员.对象可以嵌套到任何深度,其中存在惰性val.例如:
object TestShallow { lazy val value1 = 1 } object TestDeep { lazy val value1 = 1 object NestedObj { lazy val value2 = 2 } } 这是我到目前为止: import scala.reflect.ClassTag import scala.reflect.runtime.universe._ def evalMemberValues[A: TypeTag](topLevelObj: A)(implicit c: ClassTag[A]): Unit = { val mirror = runtimeMirror(getClass.getClassLoader) def loop[B: TypeTag](obj: B)(implicit c: ClassTag[B]): Unit = { println(s"INSPECTING: $obj: ${typeOf[B]}") val members = typeOf[B].decls.filter(_.isPublic) members.foreach { m => if(m.isTerm && m.isModule) { println(s"MODULE: $m") // THE PROBLEM IS HERE !!!: val inst = mirror.reflectModule(m.asModule).instance // type is Any loop(inst) } else if(m.isTerm && ! m.isConstructor && m.isMethod && m.typeSignature.paramLists.isEmpty && ! m.typeSignature.takesTypeArgs) { val im = mirror.reflect(obj) val value = im.reflectMethod(m.asMethod)() println(s"VAL/DEF: $m = $value") } else { println(s"OTHERS: $m") } } } loop(topLevelObj) } 它适用于第一级声明: scala> evalMemberValues(TestShallow) INSPECTING: $line7.$read$$iw$$iw$$iw$$iw$TestShallow$@1669f4e5: TestShallow.type OTHERS: constructor TestShallow VAL/DEF: lazy value value1 = 1 但是,它无法正确递归: scala> evalMemberValues(TestDeep) INSPECTING: $line11.$read$$iw$$iw$$iw$$iw$TestDeep$@3c2f310c: TestDeep.type OTHERS: constructor TestDeep VAL/DEF: lazy value value1 = 1 MODULE: object NestedObj INSPECTING: $line11.$read$$iw$$iw$$iw$$iw$TestDeep$NestedObj$@4f1f2f84: Any OTHERS: method == OTHERS: method != OTHERS: method equals OTHERS: method hashCode OTHERS: method toString OTHERS: method getClass OTHERS: method isInstanceOf OTHERS: method asInstanceOf OTHERS: method ## 正如您所看到的问题在于这一行: val inst = mirror.reflectModule(m.asModule).instance 因为它给了我一个类型为Any的实例,信息丢失了.理想情况下,我会得到一个具有与m对应的正确类型的TypeTag和ClassTag细节的实例.我没有找到如何从Symbol获得它,这就是m,我猜编译器不会生成它.我也没有看到如何使用instanceOf [_]来强制转换它.也许我可以通过其他方式获得声明/成员?我发现的所有示例都没有动态获取实例类型,也没有在实例上递归以获得下一级声明. 另外,检查Symbol是val还是lazy val的更好方法是什么?我只在ModuleSymbol中看到这样的检查:isVal,isLazy这对我来说很奇怪. 解决方法
这对我有用:
import scala.reflect.runtime.universe._ def evalMemberValues[A](topLevelObj: A)(implicit c: TypeTag[A]): Unit = { val mirror = runtimeMirror(getClass.getClassLoader) def loop(obj: Any,tp: Type): Unit = { println(s"INSPECTING: $tp:") val objMirror = mirror.reflect(obj) val members = tp.decls.filter(_.isPublic) members.foreach { m => if (m.isTerm && m.isModule) { println(s"MODULE: $m") loop(mirror.reflectModule(m.asModule).instance,m.info) } else if (m.isTerm && !m.isConstructor && m.isMethod && m.typeSignature.paramLists.isEmpty && !m.typeSignature.takesTypeArgs) { val value = objMirror.reflectMethod(m.asMethod)() println(s"VAL/DEF: $m = $value") } else { println(s"OTHERS: $m") } } } loop(topLevelObj,c.tpe) } 一些解释: 我使用隐式TypeTag而不是ClassTag,因为TypeTag带有方便的tpe属性,其中包含有关检查类型的完整信息.我将此Type属性传递给循环方法. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |