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

时间:2019-01-25 22:53:08

标签: scala scala-macros

我有一个软件包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? */ }
    ???
  }

2 个答案:

答案 0 :(得分:1)

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

如果traitsealed,则可以使用ClassSymbolApi中的knownDirectSubclasses,但要注意可能的问题,取决于thisthis in circe

答案 1 :(得分:0)

我认为这是您想要的:

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