当我尝试以下代码片段时,我发现未找到变量i
。为什么会这样?
function evalMyExpr(expr,n)
for i in 1:n
eval(expr)
end
end
expr1 = Meta.parse("println(\"hello\")")
expr2 = Meta.parse("println(string(i))")
evalMyExpr(expr1,2) # ok
evalMyExpr(expr2,2) # UndefVarError: i not defined
请注意,如果我将其转换为宏,则可以使用:
macro evalMyExprMacro(expr,n)
quote
for i in 1:$n
$expr
end
end
end
@evalMyExprMacro println(string(i)) 2 # ok
总的来说,接受表达式作为参数的函数和宏之间的区别是什么?
答案 0 :(得分:3)
传递给函数的表达式只是在运行时处理的普通值。代码在传递expr2
时失败的原因是,eval
在全局范围内计算表达式(通常不建议在函数中使用eval
)。因此,由于在您的情况下可能未在全局范围中定义变量i
,因此会出现错误。请参见在全局范围内定义i
时的示例:
julia> i = 1000
1000
julia> function evalMyExpr(expr,n)
for i in 1:n
eval(expr)
end
end
evalMyExpr (generic function with 1 method)
julia> expr2 = Meta.parse("println(string(i))")
:(println(string(i)))
julia>
julia> evalMyExpr(expr2,2)
1000
1000
现在-在marcos中,表达式是在编译时处理的(在运行代码之前),因此您使用的表达式将被注入到随后执行的宏所生成的代码中。您可以使用@macroexpand
来看到效果:
julia> macro evalMyExprMacro(expr,n)
quote
for i in 1:$n
$expr
end
end
end
@evalMyExprMacro (macro with 1 method)
julia> @macroexpand @evalMyExprMacro println(string(i)) 2
quote
#= REPL[23]:3 =#
for #6#i = 1:2
#= REPL[23]:4 =#
(Main.println)((Main.string)(#6#i))
end
end
观察到变量名称已由宏处理机制更改为#6#i
,并且与for
循环中使用的变量名称匹配。