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 subroutines は sort
関数に渡すこともできます。
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 に誤った警告を出してしまうという問題があります。
- ProhibitBuiltinHomonyms misinterprets "my sub" subroutines · Issue #955 · Perl-Critic/Perl-Critic
- Support for local subs with `my sub` · Issue #946 · Perl-Critic/Perl-Critic
筆者はいずれの問題に対しても修正 pull request を提出しています。Perl-Critic の誤検知がなくなり、気兼ねなく lexical subroutines が使えるようになるとよいですね。
コメント
トラックバック
このエントリのトラックバックURL: http://nanto.asablo.jp/blog/2021/12/20/9449537/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。