ruby的多维数组是否超出界限行为?

时间:2012-03-19 08:28:55

标签: ruby arrays multidimensional-array

如果我有一个多维数组,我可以超过最终维度中的边界并得到一个nil返回,但如果我超过非最终维度的边界,我会收到一个错误。这是设计,如果是的话,是什么原因?

> 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?

2 个答案:

答案 0 :(得分:3)

在Ruby中,没有多维数组。你有一个数组,包含数组作为元素。因此,如果您获得第一个“维度”,则会返回另一个数组(如果超出外部数组的边界则为nil。)

nilNilClass的一个对象,它具有一组有限(和一小组)定义的方法。在[]上未定义使用whatever[:foo]语法时调用的NilClass方法。因此它无法返回任何东西。

通常,在nil上定义所有可能的方法是没有意义的,因为它会使人们更加困惑并且会引入大量难以检测的错误。

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

> ar[2].try(:[], 2)
=> nil

然而,这通常是不鼓励的,因为它使调试更难。相反,您应该在尝试访问数组之前检查边界(例如,使用array.length)或使用包含ar.each {|e| puts e}等循环结构。

答案 1 :(得分:1)

我不知道Matz是否曾记录为什么NilClass的设计方式如此。如果不是这样,那么我们只能猜测。我的猜测是它基于Smalltalk的行为。

nil可能是消息吃异常抛出。 Ruby有一个异常抛出nil对象。

如果你有消息 nil那么很难确定第一个在arr[1][2][3]等链式调用中返回nil的对象。我不知道这究竟是多久一个问题,但它似乎是一个有效的观点。作为一个反例,Objective-C似乎可以正常使用消息 nil。

您可以修补NilClass成为消息

class NilClass
  def method_missing(*)
    nil
  end
end

或仅适用于数组

class NilClass
  def []
    nil
  end
end

使nil[]返回nil并且可以破坏现有代码

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