如何在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更合适。谢谢你的回答。我将关注这一演变,并查看宏注释建议。我认为这可能是一个有趣的选择