【问题标题】:Variable Scope issue in Macro宏中的变量范围问题
【发布时间】:2021-03-18 18:24:23
【问题描述】:

如果在 main 中定义,我有一个宏。

macro check_set(d,v)
    nm = string(v)
    quote
        global $v
        if haskey($d,$nm)
            $v = $d[$nm]
        end
    end
end

但是,当我将它放入模块(在模块内定义的宏)以在函数(也在模块内定义)中使用时,我会遇到范围问题。

export setVars

function setVars(val::Dict)
   global max_iter
   @check_set val max_iter
end

我主要调用setVars(config),其中config 是预期的字典。我明白了:

错误:UndefVarError:val 未定义

添加@macroexpand 我明白了:

begin
    #= /home/dpazzula/Documents/Stuff/src/Stuff.jl:156 =#
    global max_iter
    #= /home/dpazzula/Documents/Stuff/src/Stuff.jl:157 =#
    if Stuff.haskey(Stuff.val, "max_iter")
        #= /home/dpazzula/Documents/Stuff/src/Stuff.jl:158 =#
        Stuff.max_iter = Stuff.val["max_iter"]
    end
end

所以 ERROR 是有道理的,当 val 被本地限定为函数时,它正在寻找 Stuff.val

如何让它查找本地范围的val

【问题讨论】:

标签: julia


【解决方案1】:

您的问题与macro hygiene 有关。在您的情况下,由于您希望 dv 引用宏调用环境范围内的变量名,因此您必须使用 esc“转义”它们

这将是一个与您所写内容类似的最小工作示例:

module Stuff

macro check_set(d,v)
    nm = string(v)
    d = esc(d)
    v = esc(v)
    quote
        global $v
        if haskey($d,$nm)
            $v = $d[$nm]
        end
    end
end

end #module Stuff

我们可以检查这是否扩展为预期的:

julia> @macroexpand Stuff.@check_set val max_iter
quote
    #= REPL[1]:8 =#
    global max_iter
    #= REPL[1]:9 =#
    if Main.Stuff.haskey(val, "max_iter")
        #= REPL[1]:10 =#
        max_iter = val["max_iter"]
    end
end

而且它在运行时的行为也符合预期:

julia> function setVars(val::Dict)
           Stuff.@check_set val max_iter
       end
setVars (generic function with 1 method)

julia> config = Dict("max_iter" => 42)
Dict{String,Int64} with 1 entry:
  "max_iter" => 42

julia> setVars(config)
42

julia> max_iter
42

【讨论】:

    猜你喜欢
    • 2012-09-25
    • 2016-12-18
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 2011-11-21
    相关资源
    最近更新 更多