如何识别Scala宏中的匿名类?
我有一个枚举类成员的宏。我想扩展宏,使其递归工作,方法是将内部枚举到以下形式的任何类成员中:如何识别Scala宏中的匿名类?,scala,reflection,scala-macros,Scala,Reflection,Scala Macros,我有一个枚举类成员的宏。我想扩展宏,使其递归工作,方法是将内部枚举到以下形式的任何类成员中: object obj { var name = "value" var nested = new { var x = 0 } } 在转换到宏之前我使用的运行时反射中,对我有效的对应测试是symbol.info.wilded=:=typeOf[AnyRef],但是这不能用于宏,因为在这种情况下,类型不是AnyRef,
object obj {
var name = "value"
var nested = new {
var x = 0
}
}
在转换到宏之前我使用的运行时反射中,对我有效的对应测试是symbol.info.wilded=:=typeOf[AnyRef]
,但是这不能用于宏,因为在这种情况下,类型不是AnyRef,而是它的子类(优化)
当我将类型打印到控制台时,我得到例如:
AnyRef{def x:Int;def x_=(x$1:Int):Unit}
当我列出所有基类时,我得到:
列表(,类对象,类任意)
我不能使用测试
val fName=f.name.decodedName.toString
如果(f.info.wilded=:=typeOf[AnyRef]){//在宏中尝试用按类型匹配的模式替换if-else
val anyRefType = typeOf[AnyRef]
f.info match {
case NullaryMethodType(RefinedType(List(`anyRefType`), _)) =>
q"$fName -> listMembersNested(t.$f)"
case _ =>
q"$fName -> t.$f"
}
在宏中,尝试用按类型匹配的模式替换if-else
val anyRefType = typeOf[AnyRef]
f.info match {
case NullaryMethodType(RefinedType(List(`anyRefType`), _)) =>
q"$fName -> listMembersNested(t.$f)"
case _ =>
q"$fName -> t.$f"
}
如果我调用运行时反射版本listMembersNested_A(obj)
,那么它将生成List((嵌套,pckg.App$obj$$anon$1@7ae42ce3),(名称、值))
即在if-else
中,分支字段.get
同时被选中,分支listMembersNested\u A(字段.get)
从未被选中。这是预期的行为吗?并且您的宏版本listMembers(obj)
(我定义了def listMembers[O](t:O)(隐式lmn:ListMembersTested[O]):Seq[(String,Any)]=lmn.listMembers(t)
)会生成Seq(“name”。$减$大(t.name),“嵌套”。$减$大(t.nested))
。所以我看不出运行时反射版本和宏版本的工作方式有什么区别。“如果我调用运行时反射版本”,这真的很奇怪。在我的项目中调试函数时,它为我进入ListMembersTested\u A
递归,生成的结果是“List((嵌套,List((x,0)),(name,value))”然后。当我在Scastie中尝试这一点时,我得到了与您相同的结果。这是Scala 2.12.12。只有当obj
被定义为函数中的局部变量时,我才得到我描述的行为。当它是另一个对象/类的成员时,我得到了您描述的行为。当我在ScalaTest中调试它时,它是一个局部变量。相关问题:如果我调用运行时反射版本listMembersNested_A(obj)
,那么它将生成List((嵌套,pckg.App$obj$$anon$1@7ae42ce3),(名称、值))
即在if-else
中,分支字段.get
同时被选中,分支listMembersNested\u A(字段.get)
从未被选中。这是预期的行为吗?并且您的宏版本listMembers(obj)
(我定义了def listMembers[O](t:O)(隐式lmn:ListMembersTested[O]):Seq[(String,Any)]=lmn.listMembers(t)
)会生成Seq(“name”。$减$大(t.name),“嵌套”。$减$大(t.nested))
。所以我看不出运行时反射版本和宏版本的工作方式有什么区别。“如果我调用运行时反射版本”,这真的很奇怪。在我的项目中调试函数时,它为我进入ListMembersTested\u A
递归,生成的结果是“List((嵌套,List((x,0)),(name,value))”然后。当我在Scastie中尝试这一点时,我得到了与您相同的结果。这是Scala 2.12.12。只有当obj
被定义为函数中的局部变量时,我才得到我描述的行为。当它是另一个对象/类的成员时,我得到了您描述的行为。当我在ScalaTest中调试它时,它是一个对我来说是局部变量。连接问题:很好。这真的很有效。在阅读了RefinedType
ScalaDoc之后,我认为甚至可以进行更具体的匹配NullaryMethodType(RefinedType(List(AnyRef))
,但不知何故似乎不再匹配。我现在明白了。我需要与[AnyRef]的Types进行匹配
,不是简单的AnyRef
@Suma如果更方便的话,你也可以匹配f.info.resultType match{case-definedtype(List(`anyRefType`),_)=>…
@Suma很棒。这真的很有效。在阅读definedtype
ScalaDoc I之后,尽管更具体的匹配是NullaryMethodType(ref(List(AnyRef),)
是可以制作的,但不知怎么的,它似乎不再匹配了。我现在明白了。我需要匹配[AnyRef]
的类型,而不是简单的AnyRef
@Suma,如果更方便的话,你也可以匹配f.info.resultType match{case-definedtype(List(`anyRefType`),_)=>…
@Suma
val anyRefType = typeOf[AnyRef]
f.info match {
case NullaryMethodType(RefinedType(List(`anyRefType`), _)) =>
q"$fName -> listMembersNested(t.$f)"
case _ =>
q"$fName -> t.$f"
}