Julia中for循环与列表推导式更新全局向量为何结果不同?
Julia全局向量历史存储问题解析
问题背景
存在全局向量vec需在循环中随机更新,全局向量vecvec(向量的向量)用于存储vec的历史版本:
- 用
make_vec()函数更新vec后推入vecvec,运行后vec每次循环更新符合预期,但vecvec中所有向量完全相同; - 改用
make2_vec()或make3_vec()实现时,vecvec能正确保存vec的所有历史版本。
疑问解答
疑问1:为何vecvec中存储的历史向量全部一致?
你的猜测完全正确:Julia中的数组是可变引用类型。push!(vecvec, vec)操作并没有复制vec当前的数值内容,只是将指向该数组内存地址的引用添加到vecvec中。循环过程中,make_vec()始终在修改同一个数组的元素值,最终vecvec里的所有条目都指向同一个数组的最终状态,因此所有向量看起来完全一致。
疑问2:为何make2_vec()或make3_vec()能得到预期结果?
这两个函数的核心是每次都创建了新的数组实例:
make2_vec()中,[rand(0:9) for i=1:3]会直接生成一个全新的数组对象,随后将全局变量vec指向这个新数组的内存地址。每次循环推入vecvec的都是不同数组的引用,自然能保留每次更新的历史版本;make3_vec()里先创建了局部数组vec3,修改其元素后再让全局vec指向它。每次循环都会生成一个新的vec3实例,本质也是每次向vecvec推入不同数组的引用,因此能正确保存所有历史状态。
可复现代码
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() # make2_vec and make3_vec would give the desired result, but not make_vec println(vec) push!(vecvec,vec) end print(vecvec)
内容的提问来源于stack exchange,提问作者Alexander Kurz
相关产品推荐
相关产品推荐

