Scala 宏:如何获取给定包中继承某些特征的对象列表?
Scala macros: How can I get a list of the objects within a given package that inherit some trait?
我有一个包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? */ }
???
}
如果 trait
不是 sealed
,则不能这样做。从根本上说,如果 trait
不是 sealed
,这意味着以后可以在不同的编译单元下添加新的子类。
如果 trait
是 sealed
,那么您可以使用 knownDirectSubclasses
或 ClassSymbolApi 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
}
}
我有一个包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? */ }
???
}
如果 trait
不是 sealed
,则不能这样做。从根本上说,如果 trait
不是 sealed
,这意味着以后可以在不同的编译单元下添加新的子类。
如果 trait
是 sealed
,那么您可以使用 knownDirectSubclasses
或 ClassSymbolApi 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
}
}