クロージャというのは下記のようなものだと認識していました。
use strict; use warnings; sub create_closure { my $i = 0; my $c = sub { $i++; print $i, "\n"; }; return $c; } my $c1 = create_closure(); $c1->(); # 1 $c1->(); # 2 my $c2 = create_closure(); $c2->(); # 1 $c2->(); # 2
こういう感じかー、と単純に考えていたら、引っかかったことがありました。
use strict; use warnings; sub create_closures { my @closures; for (my $i = 0; $i < 5; $i++) { push @closures, sub { print $i, "\n"; }; } return @closures; } my @closures = create_closures(); $closures[0]->(); # 5 $closures[1]->(); # 5 $closures[2]->(); # 5 $closures[3]->(); # 5 $closures[4]->(); # 5
期待してた結果は「$closures[2]->();」は「2」という結果を返してくれることです。
しかし、すべて「5」になりました。
forのループの中で随時「sub { print 1, "\n"; };」 という感じで決まっていくのかと思ったのですが違うのですね。
スコープを抜けた時点で$iの値が決まるという事でしょうか。
下記のコードでは、期待通りの結果が得られました。
use strict; use warnings; sub create_closures { my @closures; for (my $i = 0; $i < 5; $i++) { push @closures, create_function($i); } return @closures; } sub create_function { my ($i) = @_; return sub { print $i, "\n"; }; } my @closures = create_closures(); $closures[0]->(); # 0 $closures[1]->(); # 1 $closures[2]->(); # 2 $closures[3]->(); # 3 $closures[4]->(); # 4