【问题标题】:When are Scala macro annotations executed? (macro paradise)什么时候执行 Scala 宏注解? (宏观天堂)
【发布时间】:2019-04-03 09:27:38
【问题描述】:

我尝试实现 documentation 中描述的 Scala 宏注释示例。我设法在使用它们的实际项目之前编译宏注释,即@compileTimeOnly("enable macro paradise to expand macro annotations") 没有被触发,这意味着宏注释在使用之前被编译。到目前为止一切顺利。

但是,当我在实际项目中对某些值进行如下注释时:

@identity val foo: Double = 1.1
@identity val bar: String = "bar"

那么我希望在运行主项目时会发生以下打印(通过之前链接的宏注释示例):

(<empty>,List(val foo: Double = 1.1))
(<empty>,List(val bar: String = "bar"))

这是我感到困惑的地方,当我运行主项目时不会发生打印。但是,在编译主项目时,它确实会出现一瞬间作为警告?

(我使用的是 IntelliJ IDEA 和 Scala 2.12.8)

【问题讨论】:

    标签: scala macros annotations scala-macro-paradise


    【解决方案1】:

    我设法在使用它们的实际项目之前编译宏注释,即@compileTimeOnly("启用宏天堂扩展宏注释") 没有被触发,这意味着宏注释是在使用之前编译的

    不,@compileTimeOnly 被触发意味着注释在使用它的代码编译后存在。所以它没有被触发意味着宏已经在编译期间执行。由于println 在宏的主体中,而不是在转换后的代码中,因此您可以看到输出。

    如果您希望在运行项目时进行打印,则需要修改包含转换后代码的返回值,即示例中的最后两行:

    val outputs = expandees
    c.Expr[Any](Block(outputs, Literal(Constant(()))))
    

    使用quasiquotesdirectly manipulating ASTs

    未经测试,但使用类似这样的准引号应该可以工作

    object identityMacro {
      def impl(c: Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
        import c.universe._
        val inputs = annottees.map(_.tree).toList
        val (annottee, expandees) = inputs match {
          case (param: ValDef) :: (rest @ (_ :: _)) => (param, rest)
          case (param: TypeDef) :: (rest @ (_ :: _)) => (param, rest)
          case _ => (EmptyTree, inputs)
        }
        val stringToPrint = (annottee, expandees).toString
        c.Expr[Any](q"""
        println($stringToPrint)
        $expandees
        ()
        """)
      }
    }
    

    【讨论】:

    • 谢谢,这解决了我的问题!因此,如果我理解正确,它只是由使用该宏在代码中扩展的宏返回的 AST(在您的情况下使用准引号构造)?
    • 是的,没错。 identityMacro.impl 只是一个普通的 Scala 方法,它碰巧操纵 AST 并在使用 @identity 编译代码期间执行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 2015-05-02
    • 2021-08-23
    • 2011-02-05
    相关资源
    最近更新 更多