eachメソッドの返り値?
Ruby Silverの勉強をしていて、以下のようなコードの実行結果についての設問があった。
(1..10).each.reverse_each.each do |i| puts i end
実行結果は以下。
10 9 8 7 6 5 4 3 2 1
単純にeach
で取り出したものをreverse_each
で逆順にして、それをeach
で繰り返し処理するというだけなのだけれど、自分は最初のeach
の段階でレシーバである範囲オブジェクトから1
が取り出されていると考えてしまって混乱してしまった。
ポイントは、each
そのものの返り値は何かということを誤解していたことだと思う。
eachの返り値はレシーバ自体
結論から言うと、そういうことらしい。 試しにirbで以下のコードを実行してみる。
(1..10).each do |i| end => 1..10 # <= レシーバが返ってきている
レシーバが配列の場合でも、
array = [1,3,5] array.each do |n| end => [1, 3, 5] # <= やっぱりレシーバが返ってくる
こうなる。
もう一度最初のコードを見てみると、初めに呼び出されたeach
はブロックを渡されない状態で、先ほどirbで実行したのと同じように何の処理もせずにレシーバを返して次のreverse_each
に処理が移っていると考えられる。
reverse_eachもブロックついてないのになぜ逆順になるのか?
最初のコードを見てみると、reverse_each
にもブロックは渡されていないため、先ほどのeach
の例に当てはめるとレシーバがそのまま順序も変わらずに次のeach
に渡されそうなものだが、実際には2個目のeach
によって取り出される値はしっかり逆順になっていた。
これについてはリファレンスマニュアルで言及があり、曰く
ブロックを省略した場合は、各要素を逆順に辿る Enumerator を返します。
とあるので、挙動としてはこれで正しいようだ。
これ、内部的にはreverse
が呼ばれた後にeach
が呼ばれてるってだけなんじゃないかと思わなくもない。ただの想像だけれど。
今回は以上です。