我有一个字符串,例如z[2]
并且我想在上下文中eval
它,例如字典(:z => 1:10)
最好的方法是什么?
我可以让它工作,但它非常慢。
function replace_expr(expr, d::Dict)
return expr
end
function replace_expr(s::Symbol, d::Dict)
get(d, s, s)
end
function replace_expr(expr::Expr, d::Dict)
return Expr(replace_expr(expr.head, d),
[replace_expr(e, d) for e in expr.args]...)
end
function eval_with(context::Dict{Symbol, Any}, expr_string::AbstractString)
# E.g. :abc => :(s[:abc])
d = Dict(k => :(s[$(Meta.quot(k))]) for k in keys(context))
ex = parse("s -> $expr_string")
ex = replace_expr(ex, d)
return eval(ex)(context)
end
下面是测试
function make_context()
x = 1
y = "foo"
z = 2:5
Dict(
:x => x,
:y => y,
:z => z
)
end
const context = make_context()
@test eval_with(context, "x + 3") == 4
@test eval_with(context, "string(1, y, 1)") == "1foo1"
@test eval_with(context, "z[2]") == 3
@time eval_with(context, "z[2]")
# 0.004739 seconds (767 allocations: 40.728 KB)
最佳答案
这似乎是您可以更多地依赖 Julia 内置表达式求值机制的地方。 eval
采用可选参数:要在其中进行评估的模块。
您可以通过编程方式创建新模块:
julia> M = Module()
anonymous
您可以使用eval
将字典中的值分配给该模块:
julia> context = Dict(
:x => 1,
:y => "foo",
:z => 2:5
);
julia> for (k,v) in context
eval(M, :($k = $v))
end
julia> M.x
1
julia> M.y
"foo"
现在,当然,您可以在模块的上下文中评估自定义字符串。
julia> eval(M, parse("x+3"))
4
julia> eval(M, parse("string(1, y, 1)"))
"1foo1"
像这样的动态评估不会是 Julia 的闪光点。我认为这将是最好的:
julia> @time eval(M, parse("z[2]"))
0.000284 seconds (13 allocations: 672 bytes)
3
请注意,这与您上面编写的代码的语义略有不同;您的上下文中的变量仅在开始时填充......并且可能会因新的评估而更改。
还有usual caveats关于使用eval
apply。通常还有其他更好的方法来构建程序,这些方法将提高性能、更易于理解且更易于维护。
关于julia - 在字典形式的给定范围/上下文中进行评估的最佳方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41639237/