How can I eval a local variable in Julia

后端 未结 4 1140
太阳男子
太阳男子 2020-12-10 04:00
i = 50
function test()
  i = 10
  eval(:i)
end
test()  # => 50

Why does this evaluate to the global i instead of the local one? Is

相关标签:
4条回答
  • 2020-12-10 04:19

    An alternative solution with nested macros:

    macro _localeval(ex)
      esc(:($ex))
    end
    
    macro localeval(ex)
      esc(@_localeval(Meta.parse(ex)))
    end
    
    i = 50
    function test()
      i = 10
      @localeval "i"
    end
    
    test()
    
    0 讨论(0)
  • 2020-12-10 04:26

    You can't. Julia's eval always evaluates code the current module's scope, not your local scope. Calling eval in local scope is an anti-pattern and a performance killer. You can, however, construct a new function which includes a bit of user code that refers to local scope and then call that function. For example:

    # user-supplied expression
    expr = :(i^2 + 1)
    
    # splice into function body
    test = @eval function ()
        i = 10
        $expr
    end
    

    Now you can call test:

    julia> test()
    101
    

    Why is this better than calling eval inside of test as in the question? Because in the original, eval needs to be called every time you call test whereas in this usage, eval is only called once when defining test; when test is called no eval is done. So while you may call eval "at run time" in the sense of "while your application is running, getting user input" it is not called "at run time" in the sense of when the function constructed with that user input is called. The former is fine, whereas the latter as distinctly an anti-pattern.

    0 讨论(0)
  • 2020-12-10 04:35

    As @StefanKarpinski mentioned eval always evaluates in global scope, but if one really wants to evaluate something locally, there are various way to do it:

    import Base.Cartesian.lreplace
    i = 50
    function test1(expr)
      i=10
      eval(lreplace(expr,:i,i))
    end
    
    i = 50
    function test2()
      i = 10
      @eval $i
    end
    test1(:(i))  # => 10
    test2()      # => 10
    

    But my preferred method to evaluates an expression at run-time is to create a function, I think it's the most efficient:

    exprtoeval=:(x*x)
    @eval f(x)=$exprtoeval
    f(4) # => 16
    
    0 讨论(0)
  • 2020-12-10 04:36

    Depending on the application, you could eval the entire function to get at the local value of i such as @simonster describes in this answer.

    0 讨论(0)
提交回复
热议问题