created: 2023-09-06T03:01:10.359Z

perlでコードブロックの中で任意の $_ を参照させる

ライブラリなどで、渡したコードブロックの中で $_ に任意の値が代入されている状態で処理をさせるコードがある。

たとえば、FormValidator::Lite のルールを記述する際には、引数で渡した値が $_ に入った状態で処理を記述できる。

rule LESS_THAN => sub {
    $_ < $_[0];
};

↑の例は「引数で渡した値が、リクエストパラメータよりも小さい数値か」を判定するコードだが、リクエストパラメータに $_ としてアクセスさせるようになっている。

どうやればいいか

このようなコードブロックは local を使って実現する。

sub main {
    # $_ を利用しているコードブロック
    my $obj = {cb => sub { warn $_->{test} }};
    # local を使うと、このスコープ内でこれ以降呼ぶ関数は$_がセットされる
    local $_ = {test => 1};
    $obj->{cb}->();
    # $_ の値のリセットはこうやる
    local $_;
    $obj->{cb}->();
}

書いてある

A local modifies its listed variables to be "local" to the enclosing block, eval, or do FILE--and to any subroutine called from within that block.

重要なところだけもう一度引用する。

any subroutine called from within that block.

いままで local を使うと「そのスコープ内で変数を変更してくれる」というものだと思っていたが、スコープというよりも「より深いコールスタックで」というふうに理解した方がよいのかもしれない。

古代ローマ人の24時間---よみがえる帝都ローマの民衆生活
[ad] 古代ローマ人の24時間---よみがえる帝都ローマの民衆生活
アルベルト・アンジェラ, 関口 英子 (単行本)