#ruby
#ruby
Вопрос:
Может кто-нибудь, пожалуйста, скажите мне, почему я получаю «: неопределенный метод `[]’ для nil: NilClass (NoMethodError)» и как я могу это исправить, пожалуйста? Я был бы очень признателен.
def fib_recursive(n)
raise ArgumentError, "The number must be a positive integer" if n < 0
return [] if n == 0
return [0] if n == 1
return [0,1] if n == 2
seq = fib_recursive(n - 1)
seq << seq[-2] seq[-1]
puts seq
end
fib_recursive(5)
но использование этого метода работает? извините, я действительно новичок в Ruby
def fib_recursive(n)
raise ArgumentError, "The number must be a positive integer" if n < 0
return [] if n == 0
return [0] if n == 1
return [0,1] if n == 2
seq = fib_recursive(n - 1)
seq << seq[-2] seq[-1]
seq
end
p fib_recursive(5)
Комментарии:
1. Неявный возврат. Проверьте возвращаемое значение puts .
2. Когда вы сообщаете об ошибке, вы должны указать строку, в которой она произошла.
Ответ №1:
Без явного return
оператора методы ruby возвращают любую последнюю выполненную строку в методе.
Последняя строка верхнего метода puts seq
… это выведет seq
на консоль, НО вернет nil.
Таким образом, ваш fib_recursive
возвращает nil для любого значения выше 2.
seq = fib_recursive(n - 1)
seq << seq[-2] seq[-1]
Это значение seq
равно нулю, и в следующей строке вы выполняете seq[-2] и seq[-1], но seq (равный нулю) не имеет метода для []
Итак, вы можете понять, почему вы получили "undefined method [] for nil:NilClass (NoMethodError)"
Ответ №2:
Давайте сначала рассмотрим вычисления, выполняемые вторым методом, тем, который работает (для n = 5
). (Я сократил имя метода до fib
, чтобы сделать мои рисунки более понятными.)
fib(5)
seq = fib(4)
-> fib(4)
seq = fib(3)
-> fib(3)
seq = fib(2)
-> fib(2)
= <- return [0,1]
seq << 0 1
= <- return [0,1,1]
seq << 1 1
= <- return [0,1,1,2]
seq << 1 2
return [0,1,1,2,3]
fib(5)
вызывает fib(4)
, который вызывает fib(3)
, который вызывает fib(2)
. fib(2)
затем возвращается [0,1]
fib(3)
значение, которому присваивается переменная do fib(3)
. sec
fib(3)
добавляет 0 1
в массив seq
и возвращает это значение ( [0,1,1]
) в f(4)
, где оно установлено равным f(4)
переменной ‘s sec
. f(4)
затем добавляет 1 1
sec
и возвращает этот массив fib(5)
. fib(5)
повторяет эти шаги и возвращает [0,1,1,2,3]
, завершая вычисления.
Теперь давайте рассмотрим, как изменение последнего оператора с на влияет на вычисления sec
puts sec
.
fib(5)
seq = fib(4)
-> fib(4)
seq = fib(3)
-> fib(3)
seq = fib(2)
-> fib(2)
= <- return [0,1]
seq << 0 1
puts seq
= <- return nil
seq <<
nil[-2]
nil[-1]
Как вы видите puts sec
, сначала выполняется fib(3)
после того, как он получил [0,1]
from fib(2)
, присвоил этот массив своей переменной sec
и добавил 0 1
к sec
. puts sec
отображает каждый элемент sec
в отдельной строке, а затем возвращается nil
к fib(4)
. Это потому, что Kernel#puts всегда возвращает nil
.
fib(4)
присваивает его переменной sec
nil
и затем пытается выполнить nil << nil[-2] nil[-1]
. Первая задача Ruby — оценить nil[-2]
, но обнаруживает, что nil
у него нет метода []
. Поэтому она вызывает NoMethodError
исключение, отображает сообщение об исключении ( NoMethodError (undefined method '[]' for nil:NilClass)
) и идентифицирует строку, в которой оно произошло ( seq << seq[-2] seq[-1]
).