― Web Technology and Life ―

ぼくがPerlではまったクロージャーってやつの罠

2012-03-11
『Perl演算子「||」,「or」の罠』に続いて、最近でPerlはまったお話。【追記】もあります。

こんな感じでGearmanに一気に仕事を依頼して、結果を待っていたら、


my $target = +[
    {
        foo => 1,
        bar => 2,
    },
    {
        foo => 1,
        bar => 2,
    },
];

my $ts = Gearman::Client->new(
    job_servers => ['127.0.0.1']
)->new_task_set;

my $id = 0;
for my $target (@$targets) {
    $id++;

    my $arg = Data::MessagePack->pack({
        hoge => $target->{foo},
        moge => $target->{bar},
    });

    my $on_complete_code = sub {
        warn $id;
        $res->{$id} = Data::MessagePack->unpack(${$_[0]})
    };

    $ts->add_task('osigoto', \$arg, +{
        on_complete => $on_complete_code,
        retry_count => 5,
    });
}
$ts->wait;

$idが全部「2」になっちゃってダメだよってお話。


my $target = +[
    {
        foo => 1,
        bar => 2,
    },
    {
        foo => 1,
        bar => 2,
    },
];

my $ts = Gearman::Client->new(
    job_servers => ['127.0.0.1']
)->new_task_set;

my $counter = 0; #ちゃんとカウンター用の変数を用意
for my $target (@$targets) {
    $counter++;#カウンターでインクリメント
    my $id = $counter; #$idは毎回初期化して、カウンターから値を代入

    my $arg = Data::MessagePack->pack({
        hoge => $target->{foo},
        moge => $target->{bar},
    });

    my $on_complete_code = sub {
        warn $id;
        $res->{$id} = Data::MessagePack->unpack(${$_[0]})
    };

    $ts->add_task('osigoto', \$arg, +{
        on_complete => $on_complete_code,
        retry_count => 5,
    });
}
$ts->wait;

ってしないと、クロージャーの罠にはまってしまう。

これに関しては、なんでか調べていない・・・。参考情報あれば、教えてください・・・

追記

twitterとかはてぶで直接間接コメント頂きありがとうございます。かなり腑に落ちました。

  • 「closure は外側のスコープの変数がみえるようにする機構でしかないから、外側の変数を変更したら違う値がかえってくるのはあたりまえだのくらっかーですね」 by tokuhiromさん
  • 「closureにバインドされるのは「変数の値」ではなく「変数そのもの」と考えるといいかもしれません。」 by gfxさん/li>
  • 「$idが一つ外側のスコープにあるんで、$on_complete_codeの実行時に$idを参照してるからなんだろうけど」 by aloelight

どうも、クロージャーに対する理解がいまいちだった感があります。クロージャーってなんか、「スコープ外の変数を参照できて、そのときの状況を保存する」って思っていたんですが、 「そのときの変数そのものを参照し続ける」んですねー。これまた勉強になりました。みなさまありがとうございます!

【追記その2】

日曜にちょうどいいサイズのネタだったし、コミュニティのオーソリティーに反応して頂いたので、ちょっと誤解を生んだ所もあるみたいなのでタイトルを変更しておきました。タイトルに、Perlって入れているのは割と「Perl ○○○」って検索するとあまり期待した結果が返ってこないから、候補として入ってくればいいなーとおもっていれているので、そのあたりの誤解は勘弁してください・・・、できるだけ都度適切な表現に変更するようにします。

Perl update_at : 2012-03-14T00:40:46
hirobanex.netの更新情報の取得
 RSSリーダーで購読する   
blog comments powered by Disqus