昨天在ruby-china上看到关于ruby的一个很有意思的问题:
1 2 3 4 5 6 | |
这是一个无限嵌套的数组,数组允许嵌套,这很正常,不过为什么会出现无限嵌套呢? 好多人给出了各式的答案,还提到了用direct graph去表示递归数组的stackoverflow的一个问题 就是用有向图去表示了一个<<的过程,不过感觉还是没解释这个的原因。
<<
先从<<符号说起,这是一个ruby上用的很多的符号,大概表示append或push的意思,可以用于String,Array等等的类型,甚至是非这些基础类,比如rails里的1-n的关系中就有用到。
object_id
在解释之前要先说一下object_id,这个有点想C++或java里的对象的地址,简单来说就是唯一标识对象的。
在irb里,可以看到[1, 2] << [1, 2]这个的结果是和我们预期的一样的:[1, 2, [1, 2]],而查看[1, 2]的object_id,会发现
1 2 3 4 5 6 | |
也就是说,看似一样的前后的[1, 2]其实并不一样,也就是说两个不同的对象(object_id),比如a和b,a << b所得到的结果是正常的。
而n << n的结果为什么有点出乎意料呢?
My explanation
在我看来这应该只是Matz做的一个约定或他对于这种情况——<<作用于自身——的解释和理解吧。
而我的解释是这样的,在<<右边的n作用于左边的n时,左边的n就发生了变化,变成了[1, 2, [1, 2]],到这里还是很正常的。
但是,问题来了,加入把这个过程放慢的话,左边的n发生了变化,右边的n也要发生变化啊,所以右边的n就也变成了[1, 2, [1, 2]]。
但还没完,右边的n正在作用于左边的n,所以左边的n其实就又成了[1, 2, [1, 2, [1, 2]]].
如此下去,是没完没了了,所以就变成了无限的嵌套数组,无限的递归下去了。这里应该也可以报错的吧,不过Matz还是选择了用[...]来代表无限的递归嵌套。
Hash也是可以有这样的结果的(来自@hooopo):
1 2 3 4 | |
应该是因为Array和Hash允许嵌套的形式,所以会出现这种情况,换种类型就不一定了,比如String:
1 2 3 4 | |
当然,这仅仅是个人对于ruby里这样的结果的一个思考和猜想,至于真正原因,恐怕还要问Matz