Неопределенный метод Фибоначчи `[]’ для nil: NilClass Ruby

#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] ).