使用 !push 更新和存储全局 Julia 数组

Update and store a global Julia array with !push

我对 Julia 1.0.3 处理全局变量的方式有些疑惑。有没有办法使用 !push 更新全局数组?

在玩REPL的时候,我想更新一个全局变量,然后push!把结果存到一个全局数组中。

var = [1]
res = []

for i in 1:5
  global var
  global res
  push!(var,i)
  print(string(var,"\n"))
  push!(res,var)
end

但是res中存储的值如下:

 [1, 1, 2, 3, 4, 5]
 [1, 1, 2, 3, 4, 5]
 [1, 1, 2, 3, 4, 5]
 [1, 1, 2, 3, 4, 5]
 [1, 1, 2, 3, 4, 5]

而我希望这样:

[1, 1]
[1, 1, 2]
[1, 1, 2, 3]
[1, 1, 2, 3, 4]
[1, 1, 2, 3, 4, 5]

特别令人费解,因为行为似乎与变量而不是数组的预期一致:

var = 1
res = []

for i in 1:5
  global var
  global res
  var = var + i
  print(string(var,"\n"))
  push!(res, var)
end

给出预期结果:

  2
  4
  7
 11
 16

我显然遗漏了一些东西。

您正在将 相同的 var 数组 推送到 res 数组中的每个位置。例如:

julia> var = [1]
1-element Array{Int64,1}:
 1

julia> res = [var, var]
2-element Array{Array{Int64,1},1}:
 [1]
 [1]

julia> var[1] = 2
2

julia> res
2-element Array{Array{Int64,1},1}:
 [2]
 [2]

res 数组 中的两个元素都是 var 本身。因此,如果您修改 var(使用 push! 或索引赋值等),那么无论您如何访问它,您都会看到这些修改。

数字不会出现这种情况,因为您无法修改数字本身。您可以更改 哪个 数字存储在数组中,但您不能更改数字 1 以代表 2 以前使用过 1 的任何地方— 这相当于这里发生的事情。

要解决此问题,您通常需要在 for 循环内(而不是在循环外)创建 var 数组。但在这种情况下,由于您正在向 var 迭代添加内容并希望保存该中间状态,因此您可以使用 copy:

julia> for i in 1:5
         global var
         global res
         push!(var,i)
         print(string(var,"\n"))
         push!(res,copy(var))
       end
Any[1]
Any[1, 2]
Any[1, 2, 3]
Any[1, 2, 3, 4]
Any[1, 2, 3, 4, 5]

julia> res
5-element Array{Any,1}:
 Any[1]
 Any[1, 2]
 Any[1, 2, 3]
 Any[1, 2, 3, 4]
 Any[1, 2, 3, 4, 5]