如何使用 scala 反射 API 获取所有包含的类 [英] How to use scala reflection API to get all contained classes

查看:127
本文介绍了如何使用 scala 反射 API 获取所有包含的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我上过这样的课:

trait ThirdParty { def invoke = println("right") }

trait WeatherIcon { def invoke = println("wrong") }

class MyClass {

    object objA extends ThirdParty

    object objB extends WeatherIcon

}

如果是 ThirdParty 类的实例,我如何使用 Scala 反射 API 遍历包含的对象并调用方法?

How can I use the Scala reflection API to iterate through the contained objects and invoke a method if it is an instance of a ThirdParty class?

推荐答案

根据 soc 写的内容,我得到了这个:

Based on what soc wrote, I got this:

import scala.reflect.runtime.universe._
val members = typeOf[MyClass].members.filter(_.typeSignature match {
  case tpe if tpe <:< typeOf[ThirdParty] => true
  case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] => true
  case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] => true
  case _ => false
})

让我解释一下模式匹配.valobject 的类型可以直接比较,但函数的类型略有不同.在这里,我匹配没有参数列表的方法和具有零元参数列表的方法.

Let me explain the pattern match. The type of a val or an object can be compared directly, but functions have a slightly different type. Here I'm matching against methods with no parameter lists, and methods with a zero-arity parameter list.

与 soc 的回答相比,这里有一些差异.首先,我使用 members 而不是 declarations.这将返回继承的成员以及那些在 MyClass 本身上声明的成员.

There are some differences here compared to soc's answer. First, I use members instead of declarations. That returns inherited members as well as those that are declared on MyClass itself.

其次,我检查它是一个值成员,而不是一个类型成员.您只能对值调用方法,因此它看起来是一个合理的限制,尽管可能没有必要.更新.isValue 方法在 2.10.0-RC1 中不再可用,所以我删除了检查.

Second, I check that it is a value member, as opposed to a type member. You can only invoke methods on values, so it looked a reasonable restriction, though maybe unnecessary. upd. The isValue method is no longer available in 2.10.0-RC1, so I removed the check.

最后,我使用 <:< 而不是检查每个父级是否相等.

Finally, I use <:< instead of checking each parent for equality.

现在,到调用.我将更改上面的代码,因为调用取决于您拥有的成员类型,因此我们最好同时进行过滤和调用.我也打算从 members 更改为 nonPrivateMembers,假设这是想要的.更新.nonPrivateMembers 在 2.10.0-RC1 中不再可用,如有必要,请使用 filter(!_.isPrivate).

Now, to the invocation. I'm going to change the code above since invocation depends on what kind of member you have, so we'd best do filtering and invocation at the same time. I'm going to change from members to nonPrivateMembers as well, assuming that's what is wanted. upd. nonPrivateMembers is no longer available in 2.10.0-RC1, use filter(!_.isPrivate) if necessary.

而且我还将避免使用 typeOf,它不适用于 REPL 上的镜像.更新.在 2.10.0-RC1 中 typeOf 运行良好,但我会保持实现的框架不变.

And I'll also avoid using typeOf, which won't work with mirrors on the REPL. upd. In 2.10.0-RC1 typeOf is working finely, but I'll keep the skeleton of the implementation unchanged.

以上基本上都是关于事物的结构:一个类型的成员是什么,它们是什么类型的成员,等等.当你想使用这些东西时,你需要镜子.

All of the above is basically concerned with the structure of things: what the members of a type are, what kind of members they are, and so on. When you want to use this stuff, in you need mirrors.

每当你有一个符号或类型的东西——一个类、方法、obj 等——你通过一个镜像对那个东西采取行动.要(反射性地)作用于对象的实例,您需要一个实例镜像.要对方法执行操作,您需要一个方法镜像,等等.

Whenever you have a symbol or a type for something -- a class, method, obj, etc -- you act on that thing through a mirror. To act (reflectively) on an instance of an object, you need an instance mirror. To act on a method, you need a method mirror, and so on.

所以让我们尝试构建一个函数来执行请求:

So let's try to build a functon to do what's requested:

import scala.reflect.runtime.universe._
def invoke[Target : TypeTag](obj: Any): Seq[Target] = {
  val mirror = runtimeMirror(obj.getClass.getClassLoader)
  val insMirror = mirror reflect obj
  val originType = insMirror.symbol.typeSignature
  val targetType = typeTag[Target].tpe

  val members = originType.members

  val result = members collect (member => member.typeSignature match {
    case tpe if tpe <:< typeOf[ThirdParty] =>
      if (member.isModule)
        (insMirror reflectModule member.asModule).instance
      else
        (insMirror reflectField member.asTerm).get
    case NullaryMethodType(tpe) if tpe <:< typeOf[ThirdParty] =>
      (insMirror reflectMethod member.asMethod).apply()
    case MethodType(Nil, tpe) if tpe <:< typeOf[ThirdParty] =>
      (insMirror reflectMethod member.asMethod).apply()
  })

  result.map(_.asInstanceOf[Target]).toSeq
}

请注意,使用 Scala 2.10.0-M4 无法恢复嵌套模块——这在 M5 或 RC1 中应该是可能的.要使用 M4 测试此代码,请将模块代码替换为 null.

Note that nested modules cannot be recovered with Scala 2.10.0-M4 -- that should be possible with M5 or RC1. To test this code with M4, replace the module code with null.

这是一个示例:

scala> class MyClass {
    object objA extends ThirdParty
    object objB extends WeatherIcon
    val aVal = new ThirdParty {}
    val bVal = new WeatherIcon {}
    def aDef = new ThirdParty {}
    def bDef = new WeatherIcon {}
    def anotherDef() = new ThirdParty {}
    def yetAnotherDef() = new WeatherIcon {}
  }
defined class MyClass


scala> invoke[ThirdParty](new MyClass)
res88: Seq[ThirdParty] = List(MyClass$$anon$5@c250cba, MyClass$$anon$3@54668d90, MyClass$$anon$1@18d8143a, null)

这篇关于如何使用 scala 反射 API 获取所有包含的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆