我在下面粘贴了完整的 MWE。由于篇幅有点长,我先来分解一下。
任务:我有一个全局向量vec,它将在循环中随机更新。我有一个全局向量vecvec(向量的向量),它应该存储vecs 的历史记录。
尝试的解决方案(不起作用):该函数make_vec()随机更新vec. 我将其放入循环中,如下所示。
for i in 1:5
make_vec()
println(vec)
push!(vecvec,vec)
end
Run Code Online (Sandbox Code Playgroud)
运行这个(或者更确切地说下面的 MWE),我们可以从打印输出中看到,全局变量在每一轮循环中都按预期vec进行了更新。make_vec()但:
问题 1:为什么收集的历史记录中的所有向量都vecvec相同?
我可以猜测这个问题的答案,即push!不推送实际向量vec,而仅推送对 的引用vec。因此,当我在vecvec循环完成后检查时,所有条目都与vec.
但这又提出了另一个问题。
问题 2:在下面的 MWE 中,我添加了make_vec(). 特别是,make_vec2()( make_vec3()isimilar) 与 for 循环相同,make_vec()但用列表理解替换了 for 循环。为什么make_vec()在循环中替换会make_vec2()给出不同的结果(实际上是期望的结果)?
vec = [1,2,3]
vecvec = []
function make_vec()
for i in 1:3
vec[i] = rand(0:9)
end
end
function make2_vec()
global vec = [rand(0:9) for i=1:3]
end
function make3_vec()
local vec3 = [1,2,3]
for i in 1:3
vec3[i] = rand(0:9)
end
global vec = vec3
end
for i in 1:5
make_vec() # make_vec2 and make_vec3 would give the desired result, but not make_vec
println(vec)
push!(vecvec,vec)
end
print(vecvec)
Run Code Online (Sandbox Code Playgroud)
我在内核为 1.8.3 的 Jupyter 笔记本中运行它。
在
for i in 1:3
vec[i] = rand(0:9)
end
Run Code Online (Sandbox Code Playgroud)
您不会更改绑定的值(在本例中vec为数组)。相反,您只需更改存储在数组中的元素。这通常称为就地更新。
另一方面:
global vec = [rand(0:9) for i=1:3]
Run Code Online (Sandbox Code Playgroud)
分配一个新向量并将这个新值绑定到vec变量。这意味着您不是更新某个容器中的值,而是替换该容器。
与以下相同:
local vec3 = [1,2,3]
for i in 1:3
vec3[i] = rand(0:9)
end
global vec = vec3
Run Code Online (Sandbox Code Playgroud)
分配local vec3 = [1,2,3]新容器并将global vec = vec3该新容器绑定到vec变量。
这清楚吗?
附带说明 - 最好不要像 Base Julia 中定义的函数名vec一样用作变量名。vec