Perl で関数内に関数を定義する2021年12月20日 21時08分

この記事は Perl アドベントカレンダーの 20 日目の分です。


Perl コードを書いていて、関数内で関数を定義したいと思ったことはありませんか? 普通に sub foo { ... } の中に sub bar { ... } を書けばよいのでは思われるかもしれませんが、それだと関数が局所的にならず外部に露出してしまいます。

package MyPackage {
    sub foo {
        sub bar { 42 }
        return bar();
    }
}
# foo 関数の外部からも bar 関数を呼び出せる。
say MyPackage::bar(); # => 42

無名関数のコードリファレンスを使うこともできますが、見た目がちょっと煩雑ですね。

package MyPackage {
    sub foo {
        my $bar = sub { 42 };
        return $bar->();
    }
}

そこで lexical subroutines の出番です。my sub foo { ... } または state sub foo { ... } と書くことで、局所的な関数を定義できます。Perl 5.18 で試験的に導入された機能で、Perl 5.26 から本採用となり警告なしで使えるようになりました。

package MyPackage {
    sub foo {
        my sub bar { 42 }
        return bar();
    }
}
# foo 関数の外部からは bar 関数を呼び出せない。
say MyPackage::bar(); # => Undefined subroutine &MyPackage::bar called

lexical subroutinessort 関数に渡すこともできます。

my sub compare { $b <=> $a }
my $array_1 = [ sort compare 1, 8, 2, 3, 5 ];
my $array_2 = [ sort compare 4, 7, 6, 0, 9 ];
say @$array_1; # => 85321
say @$array_2; # => 97640

注意点として、Perl の lint である Perl-Critic には、バージョン 1.140 時点で lexical subroutines に誤った警告を出してしまうという問題があります。

筆者はいずれの問題に対しても修正 pull request を提出しています。Perl-Critic の誤検知がなくなり、気兼ねなく lexical subroutines が使えるようになるとよいですね。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※投稿には管理者が設定した質問に答える必要があります。

名前:
メールアドレス:
URL:
次の質問に答えてください:
「ハイパーテキストマークアップ言語」をアルファベット4文字でいうと?

コメント:

トラックバック

このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2021/12/20/9449537/tb