Операторы возврата внутри procs, lambdas и блоков

У меня возникли проблемы с пониманием того, как return работает в блоках, procs и lambdas.

Например, в следующем случае, почему работает batman_ironman_proc, а batman_yield выдает ошибку?

def batman_ironman_proc
  victor = Proc.new { return "Batman will win!" }
  victor.call
  "Iron Man will win!"
end

def batman_yield
    yield
    "Iron man will win!"
end

victor = Proc.new { return "Batman will win!" }

puts batman_ironman_proc 
#batman_yield(&victor) === This code throws an error.

Ответ 1

Как один ответ в связанном вопросе показывает:

Ключевое слово return всегда возвращается из метода или лямбда в текущем контексте. В блоках он будет возвращен из метода, в котором было определено замыкание. Нельзя заставить вернуться из метода вызова или лямбда.

Ваш первый пример был успешным, потому что вы определили victor в той же функции, из которой вы хотели вернуться, поэтому return был законным в этом контексте. Во втором примере victor был определен на верхнем уровне. Таким образом, эффект от этого return будет не возвращаться из batman_yield (метод вызова), но [если он был действителен] для возврата из самого верхнего уровня (где Proc).

Уточнение:, пока вы можете получить доступ к возвращаемому значению блока (т.е. "Значение последнего выражения, оцениваемого в блоке, возвращается к методу в качестве значения доходности" - как за ваш комментарий), вы не можете использовать ключевое слово return по указанной выше причине. Пример:

def batman_yield
    value = yield
    return value
    "Iron man will win!"
end

victor = Proc.new { return "Batman will win!" }
victor2 = Proc.new { "Batman will win!" }

#batman_yield(&victor) === This code throws an error.
puts batman_yield(&victor2) # This code works fine.

Ответ 2

Я исхожу из фона C и как я объясню, когда вы вызываете функцию, которую вы устанавливаете для номера команды возврата, и регистр, в котором будет сохранено возвращаемое значение. В случае proc и block команда return не установлена, потому что они встроены или выведены в одну область, но они все равно могут вернуть возвращаемое значение, поскольку это независимые функции. Таким образом, без команды return proc/block даются нам LocalJumpError, а если мы просто хотим вернуть значение, это нормально.