如何识别 Scala 宏中的匿名类? [英] How to recognize an anonymous class in a Scala macro?
问题描述
我有一个枚举类成员的宏.我想扩展宏,以便它通过在表单中将内部枚举到任何类成员中来递归地工作:
I have a macro which enumerates class members. I would like to extend the macro so that it works recursively by enumerating inside into any class members in a form:
object obj {
var name = "value"
var nested = new {
var x = 0
}
}
在过渡到宏之前我使用的运行时反射中,对我来说效果很好的相应测试是symbol.info.widen =:= typeOf[AnyRef]
,但是这不能用于宏,因为在这个 can 中类型不是 AnyRef,而是它的子类(细化).
In a runtime reflection I have used before transitioning to macros the corresponding test which works well for me is symbol.info.widen =:= typeOf[AnyRef]
, however this cannot work with macro, as in this can the type is not AnyRef, but its subclass (refinement).
当我将类型打印到控制台时,我得到例如:
When I print the type to the console, I get e.g.:
AnyRef{def x: Int;def x_=(x$1: Int): 单位}
当我列出所有基类时,我得到:
When I list all base classes, I get:
List(
我不能使用测试 <:
I cannot use a test <:< typeOf[AnyRef]
, as almost anything would pass such test.
我该如何测试?
这是函数的反射版本,工作正常:
Here is the reflection version of the function, working fine:
def listMembersNested_A(m: Any): Seq[(String, Any)] = {
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
val anyMirror = currentMirror.reflect(m)
val members = currentMirror.classSymbol(m.getClass).toType.members
val items = for {
symbol <- members
if symbol.isTerm && !symbol.isMethod && !symbol.isModule
} yield {
val field = anyMirror.reflectField(symbol.asTerm)
symbol.name.decodedName.toString.trim -> (if (symbol.info.widen =:= typeOf[AnyRef]) {
listMembersNested_A(field.get)
} else {
field.get
})
}
items.toSeq
}
它的宏对应物(它是一个物化宏):
Its macro counterpart (it is a materialization macro):
def impl[O: c.WeakTypeTag](c: blackbox.Context): c.Expr[ListMembersNested[O]] = {
import c.universe._
val O = weakTypeOf[O]
val dive = O.members.sorted.collect {
case f if f.isMethod && f.asMethod.paramLists.isEmpty && f.asMethod.isGetter =>
val fName = f.name.decodedName.toString
if (f.info.widen =:= typeOf[AnyRef]) { /// <<<<<< this does not work
q"$fName -> listMembersNested(t.$f)"
} else {
q"$fName -> t.$f"
}
}
val r = q" Seq(..$dive)"
val membersExpr = c.Expr[Seq[(String, Any)]](r)
reify {
new ListMembersNested[O] {
def listMembers(t: O) = membersExpr.splice
}
}
}
推荐答案
在你的宏中尝试用类型匹配的模式替换 if-else
In your macro try to replace if-else
with pattern matching by types
val anyRefType = typeOf[AnyRef]
f.info match {
case NullaryMethodType(RefinedType(List(`anyRefType`), _)) =>
q"$fName -> listMembersNested(t.$f)"
case _ =>
q"$fName -> t.$f"
}
这篇关于如何识别 Scala 宏中的匿名类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!