昨天在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