Ryo*_*Oka 0 macros enums scala
我试着收集一个密封班的孩子们:
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))
}
}
}
Run Code Online (Sandbox Code Playgroud)
我测试了这个:
sealed trait Foo
case object Moo extends Foo
println(Enum.values[Foo])
Run Code Online (Sandbox Code Playgroud)
然后编译器声称:
object Moo is not a value
Run Code Online (Sandbox Code Playgroud)
所以我尝试了它的同伴:
...
val elemIdents = elemSymbols.map(s => Ident(s.asCaseClass.companion))
...
Run Code Online (Sandbox Code Playgroud)
然后编译器声称:
not found: value <none>
Run Code Online (Sandbox Code Playgroud)
所以对象Moo不是XD对象
我究竟做错了什么?
编译器代码中的这个图描述了类模块和模块类的一般情况(内部对象称为模块):
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
Run Code Online (Sandbox Code Playgroud)
这些东西都是内部的.但是,重要的是要看到,当您查询特征的子类时,您将获得模块类而不是模块本身.
您可以通过调用module模块类符号从模块类到模块:
val elemIdents = for {
elemSym <- elemSymbols
if elemSym.isModuleClass // TODO fail if not a module class? Ignore?
} yield Ident(elemSym.asClass.module)
Run Code Online (Sandbox Code Playgroud)