Scala 宏中访问参数值时的编译问题 [英] Compilation issue when accessing parameter value in Scala macro

查看:37
本文介绍了Scala 宏中访问参数值时的编译问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个最小示例的调用代码似乎可以编译(Eclipse Indigo SR2,Scala v2.10.20),但包含调用代码的项目标有红色叉号(我不清楚如何为此获得进一步的诊断).不生成类文件.如果我用一些文字替换 param.value 例如1、调用代码编译.

The calling code for this minimal example appears to compile (Eclipse Indigo SR2, Scala v2.10.20), but the project containing the calling code is marked with a red cross (not clear to me how to get further diagnostics for this). No class files are generated. If I replace param.value with some literal e.g. 1, the calling code compiles.

这是一个已知问题吗?有解决方法吗?

Is this a known problem? Is there a workaround?

def myMacro( param : Int ): Int = macro myMacroImpl( param )

def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
    import c.universe._

    c.Expr( Literal( Constant( param.value ) ) )         
}

推荐答案

首先,宏定义的语法不要求(或允许)你指定宏实现方法的参数,所以你有的代码永远不应该编译,即使在实现中有文字.请参阅下面的示例以了解正确的语法.

First of all, the syntax of macro definitions doesn't require (or allow) you to specify the parameters to the macro implementation method, so the code you have should never compile, even with a literal in the implementation. See my examples below for the correct syntax.

接下来,Expr.value 不幸的是一个谎言.考虑宏方法的参数是变量的情况.变量的值在编译时不是(并且在一般情况下不可能)已知,但您正在尝试使用该值创建编译时文字常量.这根本行不通.

Next, Expr.value is unfortunately a lie. Think about the case where the argument to the macro method is a variable. The value of the variable isn't (and in the general case couldn't be) known at compile-time, and yet you're trying to make a compile-time literal constant with that value. It's just fundamentally not going to work.

您有多种选择,可能适用也可能不适用,具体取决于您尝试执行的操作.例如,假设我们需要将 param 值加一并返回结果.如果我们希望添加在编译时发生,当我们没有得到编译时文字时,我们必须抛出一个(编译时)异常:

You have a couple of options, which may or may not be applicable depending on what you're trying to do. Suppose we need to add one to the param value and return the result, for example. If we wanted the addition to happen at compile-time, we'd have to throw a (compile-time) exception when we don't get a compile-time literal:

def myMacro(param: Int): Int = macro myMacroImpl

def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
  import c.universe._

  val p = param.tree match {
    case Literal(Constant(p: Int)) => p
    case _ => c.abort(c.enclosingPosition, "param must be a literal value!")
  }

  c.literal(p + 1) // Or, equivalently: c.Expr(Literal(Constant(p + 1))
}

另一种选择是围绕 param 表达式构建一棵树.例如,下面也返回了 param 的后继,但加法是在运行时进行的,该方法可以处理非文字参数:

Another option would be to build a tree around the param expression. For example, the following also returns the successor to param, but the addition is performed at runtime, and the method can handle non-literal arguments:

def myMacro(param: Int): Int = macro myMacroImpl

def myMacroImpl(c: Context)(param: c.Expr[Int]): c.Expr[Int] = {
  import c.universe._

  c.Expr(
    Apply(Select(param.tree, newTermName("$plus")), c.literal(1).tree :: Nil)
  )
}

不过,我们不会同时获得编译时添加和任意 param 表达式.

We're just not going to get both compile-time addition and an arbitrary param expression, though.

这篇关于Scala 宏中访问参数值时的编译问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆