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
我希望r = 3但事实证明它是r = 4.如果我删除了确保代码,则预期r = 3。为什么?
def foo
puts "in foo"
s = yield
puts "s = #{s}"
return 2
end
r = bar
in foo
in bar block
=> 3
答案 0 :(得分:4)
它是"展开堆栈"的Ruby的特色。从块。您的退货如何逐步运作:
bar
区块返回3。 return_value
= 3并且Ruby标记它是来自块的返回值,因此它应该展开堆栈并从父函数返回3。如果没有foo
部分,则根本不会返回ensure
。从函数返回和从块返回是非常重要的区别。ensure
,而return
的{{1}}部分中还有一个ensure
。foo
的{{1}}部分return 1
之后,ensure
为1.它不是来自块的值,因此Ruby"忘记"关于之前的foo
并忘记从return_value
返回。return 3
返回1,从bar
返回foo
。此外,如果你在块中写4
而不是bar
- 它会在next 3
之后返回return 3
并执行foo
即使没有确保块。这是迭代器和枚举器的神奇Ruby特性。