如果我有一个多维数组,我可以超过最终维度中的边界并得到一个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?
答案 0 :(得分:3)
在Ruby中,没有多维数组。你有一个数组,包含数组作为元素。因此,如果您获得第一个“维度”,则会返回另一个数组(如果超出外部数组的边界则为nil。)
nil
是NilClass
的一个对象,它具有一组有限(和一小组)定义的方法。在[]
上未定义使用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