[英]Ruby return in yield block called from a method with ensure
def foo
puts "in foo"
s = yield
puts "s = #{s}"
return 2
ensure
puts "in ensure"
return 1
end
def bar
foo do
puts "in bar block"
return 3
end
return 4
end
[36] pry(main)> r = bar
in foo
in bar block
in ensure
=> 4
I'd expect r = 3 but it turns out it is r = 4. If I remove the ensure code, r = 3 is expected. 我期望r = 3,但事实证明它是r = 4.如果我删除了确保代码,则预期r = 3。 Why is it?
为什么?
def foo
puts "in foo"
s = yield
puts "s = #{s}"
return 2
end
r = bar
in foo
in bar block
=> 3
It's a Ruby's feature of "unwinding the stack" from blocks. 这是Ruby从块中“展开堆栈”的特性。 How your return works step by step:
您的退货如何逐步运作:
bar
block. bar
街区返回3。 return_value
= 3 and Ruby marks that it is a return value from block, so it should unwind the stack and return 3 from parent function. return_value
= 3并且Ruby标记它是来自块的返回值,因此它应该展开堆栈并从父函数返回3。 It would not return to foo
at all if there was no ensure
section. ensure
部分,它根本不会返回foo
。 It is very important difference between returning from functions and from blocks. ensure
, and there is one more return
in ensure
section of foo
. ensure
,并且在foo
ensure
部分还有一个return
。 return 1
in ensure
section of foo
, return_value
is 1. It is not a value from block, so Ruby "forgets" about previous return 3
and forgets to return it from bar
. foo
ensure
部分return 1
后, return_value
为1.它不是来自块的值,因此Ruby“忘记”前一次return 3
并忘记从bar
返回它。 foo
and 4
from bar
. foo
返回1,从bar
返回4
。 Moreover, if you write next 3
instead of return 3
in the block - it will return to foo
after yield
and execute puts "s = #{s}"; return 2
此外,如果你在块中写下
next 3
而不是return 3
- 它将在yield
和execute之后返回foo
并执行puts "s = #{s}"; return 2
puts "s = #{s}"; return 2
even without the ensure block. 即使没有确保块也
puts "s = #{s}"; return 2
。 This is a magical Ruby feature for iterators and enumerators. 这是迭代器和枚举器的神奇Ruby特性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.