是ruby';s多维数组越界行为是否一致?

是ruby';s多维数组越界行为是否一致?,ruby,arrays,multidimensional-array,Ruby,Arrays,Multidimensional Array,如果我有一个多维数组,我可以超出最终维度的边界并得到零返回,但是如果我超出非最终维度的边界,我会收到一个错误。这是故意的吗?如果是,原因是什么 > ar = [ [00,01,02], [10,11,12], [20,21,22] ] => [[0, 1, 2], [10, 11, 12], [20, 21, 22]] > ar[2][2] => 22 > ar[2][3] => nil > ar[3][2] NoMethodError: undefin

如果我有一个多维数组,我可以超出最终维度的边界并得到零返回,但是如果我超出非最终维度的边界,我会收到一个错误。这是故意的吗?如果是,原因是什么

> ar = [ [00,01,02], [10,11,12], [20,21,22] ]
=> [[0, 1, 2], [10, 11, 12], [20, 21, 22]]
> ar[2][2]
=> 22
> ar[2][3]
=> nil
> ar[3][2]
NoMethodError: undefined method `[]' for nil:NilClass
from (irb):32
from :0

我理解为什么会发生这种情况,但为什么没有将nil[]定义为返回nil?

在Ruby中,没有多维数组。这里有一个数组,包含数组作为元素。因此,如果您得到第一个“维”,您将得到另一个数组(如果超出外部数组的边界,则为零)

nil
NilClass
的一个对象,它有一组有限(且很小)的已定义方法。而
[]
方法,即当您使用
任何[:foo]
语法时调用的方法,只是没有在
NilClass
上定义。因此它不能返回任何东西

一般来说,在nil上定义所有可能的方法是没有意义的,因为它会使人们更加困惑,并且会引入大量难以检测的bug

但是,如果您知道自己在做什么,并且愿意处理这些影响,那么您可以使用一些框架(例如ActiveSupport for Rails)定义的方法,但它不是Ruby本身的一部分。它捕获
NoMethodError
并返回
nil
。在你的情况下,你可以使用

> ar[2].try(:[], 2)
=> nil
但是,这通常是不鼓励的,因为它使调试变得更困难。相反,您应该在尝试访问数组之前检查边界(例如,使用
array.length
)或使用包含循环结构,如
ar.each{e | puts e}
,我不知道是否有文档记录了
NilClass
的设计方式。如果不是这样,我们只能猜测。我猜这是基于Smalltalk的行为

nil
可以是消息接收或异常抛出。Ruby有一个抛出nil对象的异常

如果您有一条吃nil的消息,那么很难确定在像
arr[1][2][3]
这样的链式调用中第一个返回nil的对象。我不知道这是一个多大的问题,但这似乎是一个有效的观点。作为一个反例,Objective-C似乎可以很好地处理一条消息,即吃零

您可以将
NilClass
修补为消息进食

或仅适用于阵列

class NilClass
  def []
    nil
  end
end
两者都使
nil[]
返回一个nil,并且都可以中断现有代码

nil[][][][]
=> nil

谢谢你的回复。正如我所提到的,我确实理解上面例子中发生的事情,我只是觉得这是一个奇怪的设计选择。我确实认为,正如您所提到的,由于数组不是真正的多维数组,而是嵌套对象,因此使一致的行为在某种程度上使问题变得复杂。谢谢您的思考!正如您所提到的,我确实考虑过修补
NilClass
。这将给人始终如一的行为。在我看来,另一个选择是修补
Array
以抛出
边界外异常
,但我可以看出这会产生令人困惑的结果,因为ruby数组非常灵活。我知道我以前在ruby中读到过空对象模式,但我不记得是@Avid编写了它。这里有一些非常好的建议!啊!我只是不小心删除了我以前在网站上的评论。此外,还有一篇关于消息吃和异常抛出的简洁文章
nil
nil[][][][]
=> nil