在for循环中修改数组时的奇怪行为

时间:2015-09-26 03:41:03

标签: arrays for-loop julia

看一下这个例子:

julia> VERSION
v"0.4.0-rc1"

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

julia> baz = Array(Any,3)
3-element Array{Any,1}:
 #undef
 #undef
 #undef

julia> for i = 1:3
           foo[1] = -foo[1]
           baz[i] = foo
           println("loop",i)
           println("foo: ",typeof(foo),"->",foo)
           println("baz[",i,"]: ",typeof(baz[i]), "->", baz[i])
           println("baz: ",typeof(baz),"->",baz)
       end

loop1
foo: Array{Int64,1}->[-1,2]
baz[1]: Array{Int64,1}->[-1,2]
baz: Array{Any,1}->Any[[-1,2],#undef,#undef]
loop2
foo: Array{Int64,1}->[1,2]
baz[2]: Array{Int64,1}->[1,2]
baz: Array{Any,1}->Any[[1,2],[1,2],#undef]
loop3
foo: Array{Int64,1}->[-1,2]
baz[3]: Array{Int64,1}->[-1,2]
baz: Array{Any,1}->Any[[-1,2],[-1,2],[-1,2]]

结果对我来说意外,我认为baz应该是Any[[-1,2],[1,2],[-1,2]]

但是,如果foo不是数组,则结果是合理的。

julia> foo = 1
1

julia> baz = Array(Any,3)
3-element Array{Any,1}:
 #undef
 #undef
 #undef

julia> for i = 1:3
           foo = -foo
           baz[i] = foo
           println("loop",i)
           println("foo: ",typeof(foo),"->",foo)
           println("baz[",i,"]: ",typeof(baz[i]), "->", baz[i])
           println("baz: ",typeof(baz),"->",baz)
       end
loop1
foo: Int64->-1
baz[1]: Int64->-1
baz: Array{Any,1}->Any[-1,#undef,#undef]
loop2
foo: Int64->1
baz[2]: Int64->1
baz: Array{Any,1}->Any[-1,1,#undef]
loop3
foo: Int64->-1
baz[3]: Int64->-1
baz: Array{Any,1}->Any[-1,1,-1]

我的问题是这里发生了什么,在for-loop中分配数组的正确方法是什么?

编辑:我添加了baz = deepcopy(baz),一切都很顺利。还是想知道原因。

2 个答案:

答案 0 :(得分:4)

朱莉娅有Noteworthy Differences from other Languages 例如与MATLAB不同,Julia数组是通过引用分配的。引用是别名,或现有变量的备用名称。例如,假设您将peter作为paul的引用(别名),您可以将该人称为peter或paul。 在baz[i] = foo之后,更改foo的元素也会修改baz[i]

答案 1 :(得分:4)

这是一个常见的陷阱,因为数组foo是一个绑定。 John Myles White撰写了一篇非常好的博客文章: http://www.johnmyleswhite.com/notebook/2014/09/06/values-vs-bindings-the-map-is-not-the-territory/

顺便说一下,你应该尽量避免Any数组,这些数组很慢。您可以按照以下方式轻松完成此操作:

Array(typeof(v), 3)

或只是放置v的显式类型,例如

Array(Vector{Int}, 3)

此处,Vector{Int}相当于({1}}的另一个名称。

另请注意,您可以使用不错的Array{Int, 1}代替所有println

@show

julia> a = 3 3 julia> @show a a = 3 3 也会返回显示的值。在以前版本的Julia中,输出看起来像@show