如果在 main 中定义,我有一个宏可以工作。
macro check_set(d,v)
nm = string(v)
quote
global $v
if haskey($d,$nm)
$v = $d[$nm]
end
end
end
Run Code Online (Sandbox Code Playgroud)
但是,当我将它放在一个模块中(在模块内部定义的宏)以在函数中使用(也在模块内部定义)时,我会遇到范围问题。
export setVars
function setVars(val::Dict)
global max_iter
@check_set val max_iter
end
Run Code Online (Sandbox Code Playgroud)
在 main 中,我按预期调用setVars(config)whereconfig是一本字典。我得到:
错误: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
Run Code Online (Sandbox Code Playgroud)
所以 ERROR 是有道理的,它正在寻找Stuff.val何时val局部作用于函数。
我如何让它寻找本地范围的val?
你的问题与宏观卫生有关。在您的情况下,由于您想要d并v引用宏调用环境范围内的变量名称,因此您必须使用“转义”它们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
Run Code Online (Sandbox Code Playgroud)
我们可以检查它是否扩展到预期的范围:
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
Run Code Online (Sandbox Code Playgroud)
并且它在运行时的行为也符合预期:
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
Run Code Online (Sandbox Code Playgroud)