Что происходит во время `начала;вернуть;ensure`? - PullRequest
0 голосов
/ 16 мая 2018

Я смотрел во внутренности драгоценного камня и наткнулся на следующую схему:

def foo
  begin
    return 'foo'
  ensure
    puts 'bar'
  end
end
foo

Это выведет строки 'foo' и 'bar' в STDOUT.Как это произошло?Я наивно понимаю, что когда вы встречаете оператор return, вы извлекаете вызов из стека и возвращаете значение, указанное в return.Я полагаю, что если бы это было так, то вы бы не смогли выполнить блок ensure.Очевидно, блок ensure выполнен.Мне любопытно, как это происходит.Как реализовано это поведение?

Ответы [ 3 ]

0 голосов
/ 16 мая 2018

return присваивает методу значение, даже если выполнение идет через ensure блок.

Например:

def foo
  begin
    puts txt = 'foo'
    return txt
  ensure
    puts 'bar'
  end
  puts txt = 'baz'
  return txt
end

p foo

ставит "foo" и "bar", но не "baz". Также метод foo возвращает строку "foo".

0 голосов
/ 16 мая 2018

Это именно то, как это определено в MRI, более конкретно в функции rb_ensure в eval.c (я рассмотрел фактическую реализацию, но по сути она просто генерирует контекст выполнения Ruby, выполняетблокировать в этом контексте, а затем убедиться, что все ensure блоки выполняются один за другим:

* Equivalent to <code>begin .. ensure .. end</code>.
 *
 * Calls the function \a b_proc with \a data1 as the argument,
 * then calls \a e_proc with \a data2 when execution terminated.
 * \return The return value of \a b_proc if no exception occurred,
 *   or \c Qnil if otherwise.
 * \sa rb_rescue
 * \sa rb_rescue2
 * \sa rb_protect
 * \ingroup exception
 */
VALUE
rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE data2)
{
    ...
}

Если вам интересно, как синтаксический анализатор решит вызвать эту фракцию, посмотрите на parse.yэто часть правил для bodystmt.

0 голосов
/ 16 мая 2018

когда вы сталкиваетесь с оператором return, тогда вы

Когда MRI встречает оператор return, он что-то . Некоторые переводчики могут печатать "FOO" на принтере; который находится в комнате вашего босса:)

вытолкнуть вызов из стека и вернуть значение, указанное в return

Почти. Когда MRI встречает оператор return, он вызывает блок ensure, если он существует и , тогда выводит вызов из стека.

Дело в том, что нет обязательного правила, согласно которому return должен делать что-то особенное, выгравированное в камне. Ruby интерпретатор (и некоторые другие) делает это таким образом.

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