简体   繁体   English

从带有ensure的方法调用的yield块返回Ruby

[英]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: 您的退货如何逐步运作:

  1. You return 3 from 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. 从函数返回和从块返回是非常重要的区别。
  2. But Ruby always executes ensure , and there is one more return in ensure section of foo . 但Ruby始终执行ensure ,并且在foo ensure部分还有一个return
  3. After 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返回它。
  4. It returns 1 from 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM