Переполнение стека при игре с методами Ruby singleton в IRB


Как субъект утверждает, я испытал переполнение стека при игре с синглетными методами в IRB. Ниже приведен код, который я пробовал:

c= C.new
class << c
  def class
    "my class is #{self.class}."
  end
end

Когда я позвонил c.class, я получил:

SystemStackError: stack level too deep
Maybe IRB bug!

Я нашел ссылку на то, как настроить размеры стека , но не понимаю, какие размеры стека в первую очередь.

Вопрос: Почему я получил эту ошибку в IRB? Кроме того, как я могу продолжать экспериментировать с методами Ruby singleton/class?

4 2
irb

4 ответа:

Во-первых, существует некая вещь под названием recursion, где функция может вызвать саму себя. Это то, что вы непреднамеренно сделали в своем коде.

Во-вторых, стек-это то, что поддерживает трассировку вызова функции. Таким образом, когда достигнут конец рекурсии или глубина уровня стека, он может корректно возобновить работу программы.

Что-то вроде этого: Допустим, у вас есть функция A и функция B.

function A {
  /* some code */
  B()
  /* some more code */
}

function B {
  return / * something * /
}

Ваша машина в основном останавливает выполнение A, сохраняет состояние переменных в стеке A вызывает и выполняет B. Когда, наконец, B выходит, он выскакивает из стека и возобновляет выполнение A.

В этом конкретном примере, поскольку вы хотите определить свой собственный метод class. Следующий код должен делать:

def class
  "my class is #{super}"
end

Надеюсь, это поможет.

Вы создали объект и определили метод class для этого объекта. И тогда в этом методе вы вызываете тот же самый метод class - у вас есть бесконечная рекурсия.

Вот почему вы должны избегать использования зависящих от системы ключевых слов при определении собственных методов, в вашем примере это может быть так:
class << c
  def klass
    "my class is #{self.class}"
  end
end

Стек возникает из модели памяти компьютеров.

Для каждой программы существует heap и stack. Часть кучи сейчас не имеет значения.

Когда программа вызывает функцию, происходит несколько вещей.

  • текущая позиция программы помещается в стек
  • переменные текущей области помещаются в стек

Когда вы оставляете функцию, эти действия реверсируются в обратном порядке, чтобы воспроизвести состояние программы перед вызовом функции.

Поэтому, когда ваша функция вызывает саму себя (что она и делает), она помещает строку "my class is" и текущую позицию программы в стек и запускает функцию снова, что делает то же самое.

Это продолжается в течение многих итераций, пока вы не превысите объем стека, зарезервированного для вашей программы. (Это зависит от вашей операционной системы и, в конечном счете, от объема доступной оперативной памяти и всегда является конечным.) Это когда вы получаете это исключение. Система сообщает вам, что у нее закончилось пространство стека.

Обычно это происходит только с рекурсией, которая не имеет условия остановки.

В дополнение ко всем хорошим ответам, объясняющим, как работает стек,

class зарезервированное ключевое слово в Ruby. Метод Object#class является уникальным исключением. Вы не можете по-настоящему переопределить его.