新手问题 Ruby 中关于二维数组直接赋值的问题

keyv2 · 2017年05月09日 · 最后由 keyv2 回复于 2017年05月16日 · 4071 次阅读

定义一个二维数组 ary,我先是给 ary[0][0] 赋值为 1,再是给 ary[1][0] 赋值为 233,结果输出 ary[0][0] 居然为 233,输出整个 ary ,发现每个数组第一项都是 233

截图

本人是一名大二学生……就看过那本巨红的 ruby 基础教程,这个问题实在是难到我了……

所以想请问这到底是什么原因?如果我定义一个二维数组,并初始化两个值具体又应该怎么做?

你这数组第一维的每一个子数组都是同一个指针引用。试试 Array.new 的时候传个 block 进去吧

qinix 回复

多谢,将后一个 Array.new 通过块传入的确可以实现我的目的。 但这样定义的时候默认采取引用的方式又有什么好处呢……不是很理解这种机制的目的

keyv2 回复

文档说默认定义是适合于不可变的,比如数字。这种默认写法比较简洁,新手确实容易困惑。需要看文档。

建议学 Elixir 语言,估计就没有这类的困惑了。

chenge 回复

非常感谢,看来如果要深入学习 ruby 不看文档是不行的

另一方面,Elixir 的话,考虑到现在大二,明年打算去找实习,所以我还是想把更多时间放在基础上。

只要记住 ruby 里传递的永远是引用就好了,包括数字传的也是引用,不提供代码块,只提供一个对象引用的话,这个对象不一定是可复制的(虽然数组可以),所以 Array.new 肯定不会帮你复制

mizuhashi 回复

惊了,今天下午上课自己想了一下,然后查了一下相关资料,发现所有传递引用的说法完全可以解释并且行得通。

因为 Array.new(6,[]) 的时候,我传递的是一个数组引用,每一维都指向同一个引用,那么我在这个被引用的数组作修改,的确会影响到其他维数的数组。
而传递 block 的时候,应该是 6 次 Array.new 的时候都重新执行一次 Array.new,那么每一维都指向不同的 new 出来的数组引用。

而大佬你说的数字传递的也是引用问题,我在这里得到了充分解释,并且在我的理解范围内是正确的。

在赋值的时候,ruby 根据右值创建对象并返回该对象的引用,并不论左值是否为空,原引用对象是什么,都会将之覆盖。这种不论左值都可赋值也正是任何变量都是引用的体现是么!!!!

也许我现在才有一点点理解了动态语言,想想有点小激动……

另外的,如果以上成立,那么在 ruby 中,我们创建对象的时候返回引用,因此只能通过引用间接访问。如果一个创建的对象之后我可能不需要了,那么它只能留在那里,我们无法自主删除。然而某些对象比如数字和字符串中会用的比较频繁,那会不会引起一些内存问题呀…………

mizuhashi 回复

哦,我想起来了,我在 ruby 基础教程看到过,ruby 会对每个对象引用进行计数,如果计数个数变为 0 就会自动释放。完美!

keyv2 回复

惊了可还行,怕不是真实猛男(滑稽

不过 ruby 用的不是引用计数,是 mark and sweep: http://blog.jobbole.com/60900/

mizuhashi 回复

煞笔了煞笔了,我居然自以为这个问题已经被我完美解决了……今天回来逛逛意外的发现完全受教了。真的是非常感谢。

keyv2 关闭了讨论。 05月16日 17:19
keyv2 重新开启了讨论。 05月16日 17:19
需要 登录 后方可回复, 如果你还没有账号请 注册新账号