【问题标题】:Macros vs functions that accept expressions宏与接受表达式的函数
【发布时间】:2019-10-18 18:01:12
【问题描述】:

当我尝试下面的代码 sn-p 时,我发现变量 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

更笼统地说,接受表达式作为参数的函数和宏之间有什么区别?

【问题讨论】:

    标签: macros julia metaprogramming


    【解决方案1】:

    传递给函数的表达式只是在运行时处理的普通值。代码在传递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 循环中使用的变量名相匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      • 2014-04-17
      相关资源
      最近更新 更多