宏与接受表达式的函数
Macros vs functions that accept expressions
当我尝试以下代码片段时,我发现找不到变量 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
更笼统地说,接受表达式作为参数的函数和宏有什么区别?
传递给函数的表达式只是在 运行 时处理的正常值。代码在传递 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
循环中使用的变量名称匹配。
当我尝试以下代码片段时,我发现找不到变量 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
更笼统地说,接受表达式作为参数的函数和宏有什么区别?
传递给函数的表达式只是在 运行 时处理的正常值。代码在传递 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
循环中使用的变量名称匹配。