我有一个软件包foo.bar
,其中定义了特征Parent
,并定义了一系列对象Child1
,Child2
,Child3
。我想得到一个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? */ }
???
}
答案 0 :(得分:1)
如果trait
不是sealed
,则不能这样做。从根本上来说,如果trait
不是sealed
,则意味着以后可以在不同的编译单元下添加新的子类。
如果trait
为sealed
,则可以使用ClassSymbolApi中的knownDirectSubclasses
,但要注意可能的问题,取决于this和this 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
}
}