begin節、ensure節に明示的にreturnを書いた場合と書かなかった場合で挙動が違ったのでまとめてみた。
①begin節、ensure節どちらも明示的にreturnを書かない
begin節の値が出力されている。ensure節の値は無視されている。
def foo
begin
puts "begin"
1
ensure
puts "ensure"
2
end
end
p foo
begin
ensure
1
begin式の戻り値
begin式全体の評価値は、本体/rescue節/else節のうち 最後に評価された文の値です。
また各節において文が存在しなかったときの値 はnilです。
いずれにしてもensure節の値は無視されます。
②begin節にのみ明示的にreturnを書く
①と同じ結果。ensure節の値は無視されている。
def foo
begin
puts "begin"
return 1
ensure
puts "ensure"
2
end
end
p foo
begin
ensure
1
③ensure節にのみ明示的にreturnを書く
ensure節の値が無視されず、出力されている。
def foo
begin
puts "begin"
1
ensure
puts "ensure"
return 2
end
end
p foo
begin
ensure
2
④begin節、ensure節どちらも明示的にreturnを書く
③と同じ結果。ensure節の値が無視されず、出力されている。
def foo
begin
puts "begin"
return 1
ensure
puts "ensure"
return 2
end
end
p foo
begin
ensure
2
ensure節に明示的にreturnを書くと、戻り値がensure節の値に置き換えられる
def bar
begin
return 1 # 呼び出し元に戻る前にensure節にジャンプする
ensure
return 2 # 戻り値をこの新しい値に置き換える
end
end
p bar # => 2
参考リンク
プログラミング言語 Rubyより
ensure節は、他の制御移転処理を実行して例外が伝播するのをキャンセルすることができる。
ensure節が新しい例外を生成すると、元の例外の代わりに新しい例外が伝播する。
ensure節にreturn文が含まれていれば、例外の伝播はそこで止まり、ensure節を含むメソッドは呼び出し元に戻る。
Effective Ruby の項目25にも同じような内容が書かれているみたいです。早く電子版出てほしい。。
https://books.google.co.jp/books?id=Zl_xBQAAQBAJ&pg=PA97&lpg=PA97&dq=ensure+return+%E6%98%8E%E7%A4%BA&source=bl&ots=eDuMOf4QwE&sig=SXxom8LHAL-gfLjUzXYW8Snocg8&hl=ja&sa=X&ei=sMW4VIjBItPY8gX4vICYBg&ved=0CCMQ6AEwAQ#v=onepage&q=ensure%20return%20%E6%98%8E%E7%A4%BA&f=false
参考にしたツイート
以下のツイートにインスパイアされて記事を書きました。
参考: 武田哲也さんのRuby技術者認定試験受験記
#RubyGold ensure 節あるときの評価値はどうなるかってやつ。これ間違えた。 def m begin puts "begin" 1 ensure puts "ensure" 2 end end p m
— 武田哲也 (@__takeda) 2015, 1月 11
#RubyGold (続き)上記コードは begin ensure 1 と出力する。最後「2」じゃない! http://t.co/G0pa6Jk3sF 「いずれにしてもensure節の値は無視されます」かー。そういや昔読んだような気はするが・・
— 武田哲也 (@__takeda) 2015, 1月 11