使用 for 循环将文字插入数组中的每个表达式
Interpolating literals into each expression in an array using a for loop
我有一个函数,我想在其中使用作为参数传递给函数的内插文字来评估表达式列表,并将结果分配给新数组。以前我已经能够相当简单地做到这一点:
array_of_expr = Any[:(A * 5), :(B * 6 * T)]
arglist = [:A; :B; :T]
test_input = [1e5, 1e1, 100]
@eval begin
function interpolate_all($(arglist...))
result_array = $(Expr(:vcat, array_of_expr...))
end
end
interpolate_all(test_input...)
哪个returns预期结果:
2-element Array{Float64,1}:
500000.0
6000.0
(我知道 @eval
的代码似乎不必要地复杂——这是因为在完整版本的代码中,arglist
长约 500 项。这导致了一些编译器错误在完整版本的代码中,所以我在这里尝试循环 array_of_expr
是我测试的一部分,以找出确切的错误,同时也帮助我更好地理解 metaprogramming/variable 范围.)
我可以索引 array_of_expr
并在此 MWE 中手动评估单个元素:
@eval begin
function interpolate_one($(arglist...))
result_array = similar(array_of_expr)
println("evaluating $(array_of_expr[2])")
result_array = $(array_of_expr[2])
println(result_array)
end
end
interpolate_one(test_input...)
哪个returns:
evaluating B * 6 * T
6000.0
这是预期的行为。但是如果我尝试遍历 array_of_expr
,我会遇到各种错误。以下忽略迭代器 i
并只打印符号表达式:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, it just gives the symbolic expression, basically ignoring the $:
for i in range(1, length=length(array_of_expr))
result_array[i] = ($array_of_expr[i])
end
println(result_array)
end
end
interpolate_1by1(test_input...)
下面的报告说i
没有定义,我理解是因为expressions are evaluated in the global scope, not local:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, i is undefined:
for i in range(1, length=length(array_of_expr))
result_array[i] = $(array_of_expr[i])
end
end
end
interpolate_1by1(test_input...)
有什么方法可以让它工作吗?我已经尝试了引用的 SE 答案中的策略,但没有成功。
您可以在编译时展开循环:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
$((quote
result_array[$i] = $(array_of_expr[i])
end for i in 1:length(array_of_expr))...)
return result_array
end
end
扩展后类似于
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
result_array[1] = $(array_of_expr[1])
result_array[2] = $(array_of_expr[2])
...
return result_array
end
我有一个函数,我想在其中使用作为参数传递给函数的内插文字来评估表达式列表,并将结果分配给新数组。以前我已经能够相当简单地做到这一点:
array_of_expr = Any[:(A * 5), :(B * 6 * T)]
arglist = [:A; :B; :T]
test_input = [1e5, 1e1, 100]
@eval begin
function interpolate_all($(arglist...))
result_array = $(Expr(:vcat, array_of_expr...))
end
end
interpolate_all(test_input...)
哪个returns预期结果:
2-element Array{Float64,1}: 500000.0 6000.0
(我知道 @eval
的代码似乎不必要地复杂——这是因为在完整版本的代码中,arglist
长约 500 项。这导致了一些编译器错误在完整版本的代码中,所以我在这里尝试循环 array_of_expr
是我测试的一部分,以找出确切的错误,同时也帮助我更好地理解 metaprogramming/variable 范围.)
我可以索引 array_of_expr
并在此 MWE 中手动评估单个元素:
@eval begin
function interpolate_one($(arglist...))
result_array = similar(array_of_expr)
println("evaluating $(array_of_expr[2])")
result_array = $(array_of_expr[2])
println(result_array)
end
end
interpolate_one(test_input...)
哪个returns:
evaluating B * 6 * T 6000.0
这是预期的行为。但是如果我尝试遍历 array_of_expr
,我会遇到各种错误。以下忽略迭代器 i
并只打印符号表达式:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, it just gives the symbolic expression, basically ignoring the $:
for i in range(1, length=length(array_of_expr))
result_array[i] = ($array_of_expr[i])
end
println(result_array)
end
end
interpolate_1by1(test_input...)
下面的报告说i
没有定义,我理解是因为expressions are evaluated in the global scope, not local:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar(array_of_expr)
# this doesn't work, i is undefined:
for i in range(1, length=length(array_of_expr))
result_array[i] = $(array_of_expr[i])
end
end
end
interpolate_1by1(test_input...)
有什么方法可以让它工作吗?我已经尝试了引用的 SE 答案中的策略,但没有成功。
您可以在编译时展开循环:
@eval begin
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
$((quote
result_array[$i] = $(array_of_expr[i])
end for i in 1:length(array_of_expr))...)
return result_array
end
end
扩展后类似于
function interpolate_1by1($(arglist...))
result_array = similar($array_of_expr)
result_array[1] = $(array_of_expr[1])
result_array[2] = $(array_of_expr[2])
...
return result_array
end