首页 > 解决方案 > Scala宏:如何获取给定包中继承某些特征的对象列表?

问题描述

我有一个包foo.bar,其中定义了一个特征,Parent并定义了一系列对象Child1, 。我想获得一个包含. 我怎样才能写出这样的宏?Child2Child3List[Parent]foo.bar

现在我有以下内容:

  def myMacro(c: blackbox.Context): c.Expr[Set[RuleGroup]] = {
    val parentSymbol = c.mirror.staticClass("foo.bar.Parent")
    c.mirror.staticPackage("foo.bar").info.members
      // get all objects
      .filter { sym =>
      // remove $ objects
      sym.isModule && sym.asModule.moduleClass.asClass.baseClasses.contains(parentSymbol)
    }.map { ??? /* retrieve? */ }
    ???
  }

标签: scalascala-macros

解决方案


我想这就是你要找的:

.map(sym => c.mirror.reflectModule(sym.asModule).instance.asInstanceOf[Parent])

后期编辑:

我已经尝试在一个特征中执行此操作,而不是像上面那样的宏,并且当使用与调用它的包不同的包调用它时,它返回一个空的对象集合。通读它可能与类加载器在 Scala 中的工作方式有关,因为他们不了解所有正在加载的类,但我看到你的宏不使用类加载器,所以它可能仍然适用于你的情况。

对我来说,它在一个特征中使用这样的反射库:

import org.reflections.Reflections

import scala.reflect.runtime.universe
import scala.reflect.{ClassTag, classTag}
import scala.collection.JavaConverters._

trait ChildObjects {
  def childObjectsOf[Parent: ClassTag](containingPackageFullName: String): Set[Parent] = {
    new Reflections(containingPackageFullName)
      .getSubTypesOf(classTag[Parent].runtimeClass)
      .asScala
      .map(cls => {
        val mirror = universe.runtimeMirror(cls.getClassLoader)
        val moduleSymbol = mirror.moduleSymbol(cls)
        mirror.reflectModule(moduleSymbol).instance.asInstanceOf[Parent]
      })
      .toSet
  }
}

推荐阅读