Является ли согласованным поведение многомерного массива за пределами ruby? - PullRequest
3 голосов
/ 19 марта 2012

Если у меня есть многомерный массив, я могу превысить границы в конечном измерении и получить нулевое возвращение, но если я превышаю границы не конечного измерения, я получаю ошибку.Это из-за замысла, и если да, то в чем причина?

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

3 голосов
/ 19 марта 2012

В Ruby нет многомерных массивов.У вас есть массив, содержащий массивы в качестве элементов.Поэтому, если вы получите первое «измерение», вы получите другой массив обратно (или ноль, если вы превысили границы внешнего массива).

nil - это объект NilClass, имеющий конечное значение (и маленький) набор определенных методов.И метод [], который вызывается при использовании синтаксиса whatever[:foo], просто не определен в NilClass.Таким образом, он ничего не может вернуть.

Как правило, не имеет смысла определять все возможные методы для nil, так как это еще больше запутает людей и приведет к появлению множества трудно обнаруживаемых ошибок.

Однако, если вы знаете, что делаете, и готовы разобраться с последствиями, вы можете использовать метод try, который определяется некоторыми средами (например, ActiveSupport для Rails), ноне является частью самого Ruby.Он ловит NoMethodError и возвращает nil.В вашем случае вы могли бы использовать

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

Однако это обычно не рекомендуется, так как затрудняет отладку.Вместо этого вы должны проверить границы, прежде чем пытаться получить доступ к массиву (например, с помощью array.length) или с помощью включающих циклических конструкций, таких как ar.each {|e| puts e}.

1 голос
/ 19 марта 2012

Я не знаю, документировал ли Матц , почему NilClass спроектирован таким, какой он есть. Если это не так, то мы можем только догадываться. Я думаю, что это основано на поведении Smalltalk.

nil может быть сообщением или исключением . В Ruby есть исключение, которое выдает объект nil.

Если у вас есть сообщение , съедающее ноль, тогда трудно определить объект, который первым вернул ноль в цепочечном вызове, например arr[1][2][3]. Я не знаю, как часто это действительно является проблемой, но это кажется правильным. Как контрпример, Objective-C, кажется, прекрасно справляется с сообщением , съедающим ноль.

Вы можете исправить NilClass, чтобы стать сообщением о еде

class NilClass
  def method_missing(*)
    nil
  end
end

или только для массивов

class NilClass
  def []
    nil
  end
end

оба заставляют nil[] возвращать ноль и могут нарушить существующий код

nil[][][][]
=> nil
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...