#ruby #return #main
#ruby #Возврат #программа-точка входа
Вопрос:
Когда я запускаю следующее в основной среде в irb или pry,
return "foo"
Я получаю:
LocalJumpError: unexpected return
что и ожидалось. Но когда я пишу этот код в отдельном файле foo.rb
и делаю:
$ ruby foo.rb
в консоли он завершается без какого-либо сообщения об ошибке.
Что происходит в последнем случае?
Я подумал, что возникшая ошибка может быть удалена автоматически, и попробовал следующее в отдельном файле:
begin
return "foo"
rescue Exception => e
p e
end
и выполнил его с консоли, но это также не привело к ошибке.
Когда я помещаю код в среду, такую как модуль, он возвращает ошибку:
module A
return "foo" # >> Invalid return in class/module body
end
Комментарии:
1. В обоих случаях, из файла и из
irb
,self
контекстmain
. Это своеобразная причуда.
Ответ №1:
Возврат верхнего уровня был добавлен в качестве функции в ruby 2.4.0: https://bugs.ruby-lang.org/issues/4840
Он никогда не упоминался в объявлении о выпуске, но вы можете увидеть его в разделе «языковые изменения» в более подробном новостном сообщении.
Если вы запустите файл, который содержит return "foo"
версию ruby < 2.4.0
, вы действительно увидите ошибку типа:
foo.rb:1:in `<main>': unexpected return (LocalJumpError)
Предполагаемый вариант использования (как вы можете видеть из приведенной выше ссылки) был для «отмены require
» — например, если файл зависит от платформы, например:
require "test/unit"
return unless /mswin|cygwin|mingw|bccwin/
# ...
Было много дискуссий и споров по поводу предлагаемого синтаксиса и поведения; но выбранную реализацию, возможно, лучше всего понять, прочитав тестовые примеры реализации:
def test_return_toplevel
feature4840 = '[ruby-core:36785] [Feature #4840]'
code = <<~'CODE'
return; raise
begin return; rescue SystemExit; exit false; end
begin return; ensure exit false; end
begin ensure return; end
begin raise; ensure; return; end
begin raise; rescue; return; end
return false; raise
return 1; raise
CODE
all_assertions(feature4840) do |a|
code.each_line do |s|
s.chomp!
a.for(s) {assert_ruby_status([], s)}
end
end
end
Поскольку запись return
внутри REPL like pry
не находится на «верхнем уровне», это приводит к a LocalJumpError
вместо описанного выше специального поведения для «верхнего уровня return
«.