为什么这个Julia宏_not_需要`esc`?

Ray*_*oal 3 macros hygiene julia

unless这里找到了Julia中宏的一个例子,如下所示:

macro unless(test, branch)
  quote
    if !$test
      $branch
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

然而,当我尝试使用它时,它失败了(显然存在卫生问题,但我无法弄明白).这是我使用的测试:

x, y = 0, 1
@unless (x == 5) begin   # should execute
  y = 3
end
@unless (x == 0) begin   # should not execute
  y = 5
end
@assert y == 3           # FAILS! SAYS y is 0
Run Code Online (Sandbox Code Playgroud)

现在我可以通过转移分支而不是测试来完成这项工作:

macro unless(test, branch)
  quote
    if !$test
      $(esc(branch))
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

我的问题是:为什么只能逃避分支而不是测试呢?现在我尝试了宏扩展.在第一种情况下,没有esc,我得到这个:

julia> macroexpand(:(@unless (x == 5) begin y = 3 end))
quote  # none, line 3:
    if !(x == 5) # none, line 4:
        begin  # none, line 1:
            #2#y = 3
       end
    end
end
Run Code Online (Sandbox Code Playgroud)

现在即使两个宏参数都没有被转义,只有y被诅咒了!任何人都可以解释为什么会这样吗?(我知道第二个版本是有效的,因为当我逃离分支时,y没有被人工化,并且宏扩展到y = 3了预期.但是我完全x不知道为什么即使没有,也没有被人工化使用esc.)

Rez*_*lan 5

请参阅Julia doc:

宏结果中的变量被分类为本地或全局变量.如果将变量分配给(并且未声明为全局变量),声明为本地变量或将其用作函数参数名称,则该变量被视为本地变量.否则,它被视为全球......

因此,在这种情况下,test部分不会分配任何内容,因此它的变量被视为全局变量,但在branch某种程度上,已y分配,因此它被认为是本地的,并且为其分配新值不会y在模块范围中发生变化.