«возврат» в основной среде

#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 «.