Perlの忘備録というか何というか... まあタイトルにある通りです. 或いはSmart::Args::TypeTinyのIMCOMPATIBLE CHANGES WITH Smart::ArgsのDefault parameter can take coderef as lazy valueを読みましょう.
use strict; use warnings; use Smart::Args::TypeTiny qw(args); sub test { args my $arg1 => { isa => 'Str', optional => 1, default => sub { generator('from test1') } }, my $arg2 => { isa => 'Str', optional => 1, default => generator('from test2') }; return 1; } sub generator { my ($message) = @_; warn $message; return $message; } warn "case 1"; test(); warn "case 2"; test(arg1 => 'test'); warn "case 3"; test(arg2 => 'test'); warn "case 4"; test(arg1 => 'test', arg2 => 'test');
これを実行すると, 次のような結果になります(見やすくなるように改行を入れています):
case 1 at smart-args.pl line 22. from test2 at smart-args.pl line 17. from test1 at smart-args.pl line 17. args: from test1, from test2 at smart-args.pl line 11. case 2 at smart-args.pl line 24. from test2 at smart-args.pl line 17. args: test, from test2 at smart-args.pl line 11. case 3 at smart-args.pl line 26. from test2 at smart-args.pl line 17. # ← case 3 では arg2 が渡っていてデフォルト値が不要なのに, generator が呼び出されている from test1 at smart-args.pl line 17. args: from test1, test at smart-args.pl line 11. case 4 at smart-args.pl line 28. from test2 at smart-args.pl line 17. # ← case 4 では arg2 が渡っていてデフォルト値が不要なのに, generator が呼び出されている. arg1 も同様だけど, generator は呼び出されていない args: test, test at smart-args.pl line 11.
...要するに, default => generator()
のようにオプションを指定すると, 引数が渡ってこようが渡ってこまいが毎回generator()
を実行しますが, サブルーチンリファレンスで渡すと引数が渡ってこなかった時だけ(サブルーチンリファレンスを呼び出す形で)generator()
を実行してデフォルト値を生成するようになっています. 1
とか2
とかを渡すならともかく, generator()
で行われる処理の内容によっては, チリツモで処理時間が伸びていきそうなので, 気をつけたいところです.
ちなみに...
Smart::Argsでdefault
にサブルーチンリファレンスを渡すと, サブルーチンリファレンスそのものがデフォルトの値になりますので, 注意しましょう:
case 1 at smart-args.pl line 22. from test2 at smart-args.pl line 17. args: CODE(0x14d0c6568), from test2 at smart-args.pl line 11.