问题描述
我有一个枚举类成员的宏。我想扩展该宏,以便通过枚举内部任何类成员的形式来递归工作:
object obj {
var name = "value"
var nested = new {
var x = 0
}
}
在运行时反射中,我在过渡到宏之前使用了对我来说效果很好的对应测试,symbol.info.widen =:= typeOf[AnyRef]
,但是它不适用于宏,因为在这种情况下,类型可以不是AnyRef,而可以是其子类(完善)。
当我在控制台上打印类型时,会得到例如:
AnyRef{def x: Int; def x_=(x$1: Int): Unit}
当我列出所有基类时,我得到:
List(<refinement of AnyRef>,class Object,class Any)
我无法使用测试<:< typeOf[AnyRef]
,因为几乎所有测试都可以通过该测试。
我该如何测试?
这是函数的反射版本,可以正常工作:
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
}
它的宏对应物(它是实现宏):
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
替换为按类型匹配的模式
val anyRefType = typeOf[AnyRef]
f.info match {
case NullaryMethodType(RefinedType(List(`anyRefType`),_)) =>
q"$fName -> listMembersNested(t.$f)"
case _ =>
q"$fName -> t.$f"
}