Edited at

ensure節に明示的にreturnを書いた場合と書かなかった場合の違い

More than 3 years have passed since last update.

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式の戻り値

http://docs.ruby-lang.org/ja/2.1.0/doc/spec=2fcontrol.html#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



参考リンク

ensure節は伝播する例外や戻り値を変える


プログラミング言語 Rubyより

ensure節は、他の制御移転処理を実行して例外が伝播するのをキャンセルすることができる。

ensure節が新しい例外を生成すると、元の例外の代わりに新しい例外が伝播する。

ensure節にreturn文が含まれていれば、例外の伝播はそこで止まり、ensure節を含むメソッドは呼び出し元に戻る。


Rubyのensureはreturnを撤回できる

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技術者認定試験受験記