eachの途中で止めると再開が途中からになる話
Rubyのeach_with_indexは添字と要素が一度に取れるのでとても便利なときがある。
Perlで同じことをするには、5.12までは、ループ外に変数を置いて、ループ内でインクリメントするのが一般的だったけれど
5.12からはeach()が配列に対しても使えるようになって、添字と要素が一度に取れるようになった。
が、これを途中で止めて、再度eachを使用すると、その途中からループが始まってしまう。
内部的なイテレータの状態を保持しているらしい。
use strict; use warnings; package Hoge { sub new { bless [[1..10],[11..20],[21..30]], __PACKAGE__; } sub print_key { my $self = shift; while (my ($i, $elm) = each @$self) { while (my ($j, $val) = each @$elm) { print "$i: $j: $val\n"; return if $i == 1 && $j == 5; } } } } my $hoge = Hoge->new; $hoge->print_key; print "-------------------\n"; $hoge->print_key;
0: 0: 1 0: 1: 2 0: 2: 3 0: 3: 4 0: 4: 5 0: 5: 6 0: 6: 7 0: 7: 8 0: 8: 9 0: 9: 10 1: 0: 11 1: 1: 12 1: 2: 13 1: 3: 14 1: 4: 15 1: 5: 16 #=> 1-5でとめる ------------------- 2: 0: 21 #=> 再開は2-0から 2: 1: 22 2: 2: 23 2: 3: 24 2: 4: 25 2: 5: 26 2: 6: 27 2: 7: 28 2: 8: 29 2: 9: 30
再開は2-6と思いきや、2-0からであり、イテレータの保存は外側だけ働いたことが分かる。
ちなみに、イテレータをリセットするにはvoidにkeys()を呼べばよいとのこと。
http://perldoc.perl.org/functions/keys.html
面白いのは(注意しないといけないのは)、外側をリセットすると、ループの再開で内側のイテレータの継続が有効になるということ。
my $hoge = Hoge->new; $hoge->print_key; keys @$hoge; #=> リセット! print "-------------------\n"; $hoge->print_key;
0: 0: 1 0: 1: 2 0: 2: 3 0: 3: 4 0: 4: 5 0: 5: 6 0: 6: 7 0: 7: 8 0: 8: 9 0: 9: 10 1: 0: 11 1: 1: 12 1: 2: 13 1: 3: 14 1: 4: 15 1: 5: 16 #=> 1-5でとめる ------------------- 0: 0: 1 #=> 再開は0-0 0: 1: 2 0: 2: 3 0: 3: 4 0: 4: 5 0: 5: 6 0: 6: 7 0: 7: 8 0: 8: 9 0: 9: 10 1: 6: 17 #=> 1-1から1-5はスキップされる 1: 7: 18 1: 8: 19 1: 9: 20 2: 0: 21 2: 1: 22 2: 2: 23 2: 3: 24 2: 4: 25 2: 5: 26 2: 6: 27 2: 7: 28 2: 8: 29 2: 9: 30