Scala 宏:如何获取给定包中继承某些特征的对象列表?

Scala macros: How can I get a list of the objects within a given package that inherit some trait?

我有一个包foo.bar,其中定义了一个特征Parent,并定义了一系列对象Child1Child2Child3 .我想要一个 List[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? */ }
    ???
  }

如果 trait 不是 sealed,则不能这样做。从根本上说,如果 trait 不是 sealed,这意味着以后可以在不同的编译单元下添加新的子类。

如果 traitsealed,那么您可以使用 knownDirectSubclassesClassSymbolApi but beware of the possible issues the depend on order such as this and this in circe

我想这就是您想要的:

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

稍后编辑:

我试过在一个特征中这样做,所以不是像上面那样的宏,当用一个不同于调用它的包调用它时,它返回一个空的对象集合。通读它可能与类加载器在 Scala 中的工作方式有关,因为它们不知道正在加载的所有 类,但我看到你的宏没有使用类加载器,所以它可能仍然适用于你的案例.

对我来说,使用 Reflections 库在一个特征中是这样的:

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
  }
}