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

Lean UX 第3版 ―アジャイルなチームによるプロダクト開発 (THE LEAN SERIES)
[ad] Lean UX 第3版 ―アジャイルなチームによるプロダクト開発 (THE LEAN SERIES)
Jeff Gothelf, Josh Seiden (単行本(ソフトカバー))