我试着收集一个密封的班级孩子:
import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
object Enum {
def values[A]: Seq[A] = macro EnumImpl.values[A]
class EnumImpl(val c: Context) {
import c.universe._
implicit class SymbolOp(s: Symbol) {
def asSealedClass = s.asClass.ensuring(_.isSealed, s"$s is not sealed")
def asCaseClass = s.asClass.ensuring(_.isCaseClass, s"$s is not a case class")
}
def values[A: c.WeakTypeTag]: c.Expr[A] = {
val enumSymbol = weakTypeOf[A].typeSymbol.asSealedClass
val elemSymbols = enumSymbol.knownDirectSubclasses.toList
val elemIdents = elemSymbols.map(s => Ident(s.asCaseClass))
val elemSeqSymbol = weakTypeOf[Seq[A]].typeSymbol
c.Expr(Apply(Ident(elemSeqSymbol.companion), elemIdents))
}
}
}
我用它测试了它:
sealed trait Foo
case object Moo extends Foo
println(Enum.values[Foo])
然后编译器声称:
object Moo is not a value
所以我尝试了它的同伴:
...
val elemIdents = elemSymbols.map(s => Ident(s.asCaseClass.companion))
...
然后编译器声称:
not found: value <none>
因此对象Moo
不是对象XD
我做错了什么?
答案 0 :(得分:5)
compiler code中的这个图描述了类模块和模块类的一般情况(内部对象称为模块):
The internal representation of classes and objects:
class Foo is "the class" or sometimes "the plain class"
object Foo is "the module"
class Foo$ is "the module class" (invisible to the user: it implements object Foo)
class Foo <
^ ^ (2) \
| | | \
| (5) | (3)
| | | \
(1) v v \
object Foo (4)-> > class Foo$
(1) companionClass
(2) companionModule
(3) linkedClassOfClass
(4) moduleClass
(5) companionSymbol
这些东西都是内部的。但是,重要的是要看到,当您查询特征的子类时,您将获得模块类而不是模块本身。
您可以通过调用模块类符号上的module
从模块类到模块:
val elemIdents = for {
elemSym <- elemSymbols
if elemSym.isModuleClass // TODO fail if not a module class? Ignore?
} yield Ident(elemSym.asClass.module)