Julia 宏中的无效赋值错误

Invalid assignment error inside Julia macro

我一直在关注 this 笔记本(最初是用 Julia 0.x 编写的,我正在使用 Julia 1.7.1)。其中一个单元格定义了以下宏。

macro twice(ex)
  quote
    $ex
    $ex     
  end
end

在紧接着的下一个单元格中,将调用此宏。

x = 0
@twice println(x += 1)

在 REPL 中复制它(为简洁起见)会导致以下错误。

ERROR: syntax: invalid assignment location "Main.x" around REPL[1]:3
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

所以,我知道 x += 1 以某种方式导致了这个问题,但是在阅读了文档 (metaprogramming) 之后,我无法弄清楚 为什么这是一个分配无效 或如何解决此问题。

@macroexpand @twice println(x += 1)成功returns以下

quote
    #= REPL[1]:3 =#
    Main.println(Main.x += 1)
    #= REPL[1]:4 =#
    Main.println(Main.x += 1)
end

所以,我尝试在没有 Main. 的顶层 eval 进行此操作,并且评估成功。

x = 0
eval(quote
       println(x += 1)
       println(x += 1)
     end)

输出:

1
2

但是,如果我明确添加模块名称,它会引发不同的错误。

eval(quote
       Main.println(Main.x += 1)
       Main.println(Main.x += 1)
     end)
ERROR: cannot assign variables in other modules
Stacktrace:
 [1] setproperty!(x::Module, f::Symbol, v::Int64)
   @ Base ./Base.jl:36
 [2] top-level scope
   @ REPL[14]:3
 [3] eval
   @ ./boot.jl:373 [inlined]
 [4] eval(x::Expr)
   @ Base.MainInclude ./client.jl:453
 [5] top-level scope
   @ REPL[14]:1

我尝试了一些其他的东西,但这些是我认为可能有所作为的唯一东西。

使用esc(这“防止宏卫生传递将嵌入变量转换为gensym变量”):

julia> macro twice(ex)
         esc(quote
           $ex
           $ex
         end)
       end;

julia> x=1
1

julia> @twice println(x += 1)
2
3