在没有具体化的情况下制作代码时,Scala 宏不会编译
Scala macro does not compile when code is crafted without reify
我一直致力于复杂的编译时反射,并且发现需要使用 AST 手动编写 Scala 代码。在进行实验时,我注意到一个奇怪的编译错误,这对我来说并没有真正的意义,所以我尝试在一个测试项目中重现它。
我使用 Scala 2.10.4。
代码如下:
Macro.scala:
object Macro {
def reifyTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val expression = reify(OffsetDateTime.now())
c.echo(c.enclosingPosition, "With reify: " + show(expression.tree))
c.echo(c.enclosingPosition, "With reify (raw): " + showRaw(expression.tree))
expression
}
def manualAstTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val odtSymbol = typeOf[OffsetDateTime].typeSymbol
val now = newTermName("now")
val expression = c.Expr(
Apply(
Select(Ident(odtSymbol), now),
List()
)
)
c.echo(c.enclosingPosition, "Manual: " + show(expression.tree))
c.echo(c.enclosingPosition, "Manual (raw): " + showRaw(expression.tree))
expression
}
def reifyTest = macro reifyTestImpl
def manualAstTest = macro manualAstTestImpl
}
Tester.scala:
object Tester {
def main(args: Array[String]): Unit = {
println(Macro.reifyTest)
println(Macro.manualAstTest)
}
}
c.echo
的输出是:
With reify: OffsetDateTime.now()
With reify (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
Manual: OffsetDateTime.now()
Manual (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
我在调用 Macro.manualAstTest
.
时得到的编译错误是 value now is not a member of java.time.OffsetDateTime
正如回声的输出所示,这两个表达式是相同的——但一个有效(来自 reify
的表达式)而另一个无效(使用 apply-select 制作的表达式)。
两者之间有什么区别?
设法找到罪魁祸首。
显然 typeOf[OffsetDateTime].typeSymbol
return 是从 Scala class 中 return 编辑的符号,也就是说,没有它的静态成员。
添加 .companionSymbol
似乎 return 符号就像从 Scala 对象 return 编辑一样,也就是说,只有静态成员(顾名思义.. .)
因此,以下更改使其生效:
val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol
我一直致力于复杂的编译时反射,并且发现需要使用 AST 手动编写 Scala 代码。在进行实验时,我注意到一个奇怪的编译错误,这对我来说并没有真正的意义,所以我尝试在一个测试项目中重现它。
我使用 Scala 2.10.4。
代码如下:
Macro.scala:
object Macro {
def reifyTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val expression = reify(OffsetDateTime.now())
c.echo(c.enclosingPosition, "With reify: " + show(expression.tree))
c.echo(c.enclosingPosition, "With reify (raw): " + showRaw(expression.tree))
expression
}
def manualAstTestImpl(c: Context): c.Expr[OffsetDateTime] = {
import c.universe._
val odtSymbol = typeOf[OffsetDateTime].typeSymbol
val now = newTermName("now")
val expression = c.Expr(
Apply(
Select(Ident(odtSymbol), now),
List()
)
)
c.echo(c.enclosingPosition, "Manual: " + show(expression.tree))
c.echo(c.enclosingPosition, "Manual (raw): " + showRaw(expression.tree))
expression
}
def reifyTest = macro reifyTestImpl
def manualAstTest = macro manualAstTestImpl
}
Tester.scala:
object Tester {
def main(args: Array[String]): Unit = {
println(Macro.reifyTest)
println(Macro.manualAstTest)
}
}
c.echo
的输出是:
With reify: OffsetDateTime.now()
With reify (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
Manual: OffsetDateTime.now()
Manual (raw): Apply(Select(Ident(java.time.OffsetDateTime), newTermName("now")), List())
我在调用 Macro.manualAstTest
.
时得到的编译错误是 value now is not a member of java.time.OffsetDateTime
正如回声的输出所示,这两个表达式是相同的——但一个有效(来自 reify
的表达式)而另一个无效(使用 apply-select 制作的表达式)。
两者之间有什么区别?
设法找到罪魁祸首。
显然 typeOf[OffsetDateTime].typeSymbol
return 是从 Scala class 中 return 编辑的符号,也就是说,没有它的静态成员。
添加 .companionSymbol
似乎 return 符号就像从 Scala 对象 return 编辑一样,也就是说,只有静态成员(顾名思义.. .)
因此,以下更改使其生效:
val odtSymbol = typeOf[OffsetDateTime].typeSymbol.companionSymbol