如何在Scala中使用宏创建变量 我的问题可能是捏造的,我认为这不仅仅是一个可行的证明,而不是一些建议。 为了给您一些上下文,我将尝试在嵌入式DSL中使用不同于 val myVal = "someContent"

如何在Scala中使用宏创建变量 我的问题可能是捏造的,我认为这不仅仅是一个可行的证明,而不是一些建议。 为了给您一些上下文,我将尝试在嵌入式DSL中使用不同于 val myVal = "someContent",scala,macros,Scala,Macros,我希望能够做到这一点: assign("SomeContent","someVariable") => converted to someVariable = "SomeContent" 然后在代码的后面,变量是可用的。 通常,我们可以在REPL中使用类似的内容: assign("John","name") println("Hello " + name) 我一直在考虑使用宏(或ScalaCompiler插件,但我认为在这里它更复杂)来实现这一点。 首先,我不知道对于宏来说这是否可行

我希望能够做到这一点:

assign("SomeContent","someVariable") => converted to
someVariable = "SomeContent"
然后在代码的后面,变量是可用的。 通常,我们可以在REPL中使用类似的内容:

assign("John","name")
println("Hello " + name)
我一直在考虑使用宏(或ScalaCompiler插件,但我认为在这里它更复杂)来实现这一点。 首先,我不知道对于宏来说这是否可行

考虑到我只会操纵字符串,我从一些简单的东西开始

def assign(content: String, targetVal: String):Unit = macro assignMacro

def assignMacro(c:Context)(content: c.Expr[String], 
                           targetVal: c.Expr[String]):c.expr[Unit] = {
  import c.universe._

  c.Expr[Unit](ValDef(Modifiers(), TermName(targetVal.value),
                      TypeTree(), Literal(Constant(content.value)))
}
不幸的是,由于几个错误,它似乎失败了

  • 首先,当我试图创建一个新的术语名称时,它抱怨说,如果我确定,那么我应该调用表达式的eval。不幸的是,我不确定;)如果我尝试,它就会失败;)
  • 如果我用myVal和myContent等常量替换这个targetVal和content,我会收到第二条错误消息,如compiler found和required Unit
我有点卡住了。 首先,这可能吗?我想是的;) 我怎样才能做到这一点

谢谢你的帮助


最好的问候

在2.10和2.11中,def宏都扩展到块中,这意味着它们引入的定义成为该块的本地定义。这在宏观天堂很可能会改变,但我不确定何时以及如何改变

目前Scala中的宏没有提供将新变量透明地引入现有范围的方法。这是Scala宏演变的历史产物,这是因为我们的反射组优先考虑了黑盒宏(行为类似于常规方法的宏,完全由其类型签名描述,因此人类和程序可以将其实现视为黑盒而不遗漏任何内容)

最近对白盒宏(不适合黑盒方案的宏)的兴趣已经产生了一些结果,但这些结果尚未包含在主线Scala中。我将在明天的“奇怪的回路”演讲中详细阐述这一问题


同时,您可以查看宏注释,这些注释可能会提供您正在寻找的自由度。例如,通过适当地定义
mydsl
注释,您可以

@mydsl 
def foo = {
  assign("SomeContent", "someVariable")
  ...
}
变成

def foo = {
  someVariable = "SomeContent"
  ...
}

这在2.10中的这种形式中是不可能的,但是您可以编写类似于
val syntax=assign(“John”,“name”);导入语法。
以获得相同的效果。我使用的是2.11.0-M4。可能吗?我不这么认为,但我还不熟悉2.11的所有新特性。如果要赋值的变量名在编译时不可用,宏将如何生成赋值?(尽管我遗漏了一些东西,但同样可能)事实上,变量名必须由用户提供。最初我做了一些类似val variableName=。。。显然,它工作得很好。然后,我被问到是否可以像assign(SomeContent.to)(someVar)这样的东西。老实说,这开始有点奇怪了。我主要想知道是否可以使用宏或任何东西来实现这一点,同时保持在Scala内部(我希望避免使用解析器组合器)。这就是我在尝试Travis建议时所担心的。我在块范围内得到了变量。无论如何,这也是有意义的,因为在我看来,创建这样的变量打破了Scala创建副作用的一些原则。老实说,我只是试着写一下val name=。。。这对我很好。开始真正修改代码是一种警告,在这种情况下,外部DSL更合适。谢谢你的回答。我将关注这一演变,并查看宏注释建议。我认为这可能是一个有趣的选择