[Ruby] Ruby の for と each の違いは変数のスコープ
ハマったのでメモ。 for と each の違いです。
t = [] for i in [1,2,3] # [1,2,3].each do |i| t << Thread.new do puts "start #{i}" sleep i p Thread.current puts "end #{i}" end end p t while t[0].alive? end t[1].kill t[2].kill p t
こいつに thread.rb とか名前つけて、実行
$ ruby thread.rb start 1 start 2 start 3 [#<Thread:0x100169be8 sleep>, #<Thread:0x100169ad0 sleep>, #<Thread:0x1001699b8 sleep>] #<Thread:0x100169be8 run> end 3 [#<Thread:0x100169be8 dead>, #<Thread:0x100169ad0 dead>, #<Thread:0x1001699b8 dead>]
アレ?ちゃんと t[0] が終わってるんだし、そこは end 1 って出てほしいんだけど。
そこで、 for のところを each に変えて実行。
$ ruby thread.rb start 1 start 2 start 3 [#<Thread:0x100169b20 sleep>, #<Thread:0x1001699b8 sleep>, #<Thread:0x100169850 sleep>] #<Thread:0x100169b20 run> end 1 [#<Thread:0x100169b20 dead>, #<Thread:0x1001699b8 dead>, #<Thread:0x100169850 dead>]
こんどはちゃんと end 1 が出る。
あれーと悩んでいたら、次のページを発見。
for =>そのfor文が定義されているスコープに対して、iを定義する
http://ipcom.withgood.net/wordpress/?p=484
each=>eachブロック内でのみ生存する新たなスコープを用意し、そこでiを定義する
つまり、この場合は i がグローバルになっちゃうので、 for のループごとに i の値が書き変わっちゃうのが原因でした。
3つめのスレッドを作った時点で i の値は 3 になり、1つめのスレッドが終了したときその i の値を参照するので 3 が出力されると。
Ruby では基本的に for ではなく each を使うのがよさそうですね。。