为什么在 Julia 中使用 for 循环和列表理解更新全局向量会产生不同的结果?

Ale*_*urz 2 julia

我在下面粘贴了完整的 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 笔记本中运行它。

Bog*_*ski 5

    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