Perlのautovivificationをいろいろ実験
Modern Perlを読んでいたら、autovivificationという機能があるということを今更ながら知った。たいへん便利だ。。。癖が強いらしいので手を動かして挙動を確かめてみる。
autovivificationとは
my %users; $users{Brad}{id} = 228; $users{Jack}{id} = 229;
$users{Brad}
はまだ定義されていない(undef)はずだが、$users{Brad}{id}
で代入できている。これはperlが$users{Brad}
を自動生成しているからで、autovivificationと呼ぶ。
perldocにもしっかりと説明がある。 autovivification
実験
Perl 5.30.2で行った。
use Data::Dumper; sub func_array { my @h = @_; return @h; } sub func_ref { my ($h) = @_; return $h; } { # ハッシュ my %h; $h{empty}{aaa} = 'CCC'; $h{not_empty}{aaa} = 'ZZZ'; if (undef $h{undeff}{aaa}) {} if (exists $h{exists}{aaa}) {} func_array($h{via_func}{aaa}); warn Dumper(\%h); } { # ハッシュリファレンス my $h; $h->{empty}->{aaa} = 'CCC'; $h->{not_empty}->{aaa} = 'ZZZ'; if (undef $h->{undeff}->{aaa}) {} if (exists $h->{exists}->{aaa}) {} func_ref($h->{via_func}->{aaa}); warn Dumper($h); } { # 宣言と代入が同じ場合 my $h->{aaa}->{bbb} = 'CCC'; warn Dumper($h); }
出力結果
$VAR1 = { 'exists' => {}, 'undeff' => { 'aaa' => undef }, 'via_func' => {}, 'empty' => { 'aaa' => 'CCC' }, 'not_empty' => { 'aaa' => 'ZZZ' } }; $VAR1 = { 'not_empty' => { 'aaa' => 'ZZZ' }, 'empty' => { 'aaa' => 'CCC' }, 'via_func' => {}, 'undeff' => { 'aaa' => undef }, 'exists' => {} }; $VAR1 = { 'aaa' => { 'bbb' => 'CCC' } };
- リファレンスであろうと、なかろうと、宣言と同時に代入しようとautovivificationはされた
- 参考のQiitaの記事でも取り上げられているように、undef関数でもautovivificationされた
- キーの存在確認をするexistsですらautovivificationされた
- undefとexistsでは生成のされ方が少し違うので注意
- 関数に存在しないキーで引数として渡す際にもautovivificationされたが、最後までは生成されなかった?
no autovivification
参考で上げているQiitaの記事ではautovivificationというプラグマモジュールでautovivificationをいい感じに無効化していたため、インストールして使ってみた。
$ cpanm autovivification
# この一行を先程のコードの先頭に追加 no autovivification; # no autovivification qw/ fetch exists delete /;と同じ
出力結果
$VAR1 = { 'empty' => { 'aaa' => 'CCC' }, 'via_func' => {}, 'undeff' => { 'aaa' => undef }, 'not_empty' => { 'aaa' => 'ZZZ' } }; $VAR1 = { 'undeff' => { 'aaa' => undef }, 'empty' => { 'aaa' => 'CCC' }, 'via_func' => {}, 'not_empty' => { 'aaa' => 'ZZZ' } }; $VAR1 = { 'aaa' => { 'bbb' => 'CCC' } };
existsだけautovivificationが無効化された。metacpanに書かれているが、何も指定せずno autovivification
した場合、rvalueデリファレンス($h->{a}->{b}
が右側)・exists・deleteでautovivificationが無効化されるようだ。storeを指定すればlvalueデリファレンス($h->{a}->{b}
が左側)でも対応できる。
no autovivification qw/ fetch exists delete store /;
storeを指定すると上で示したコードは実行できないコードとなるので、適宜修正する必要がある。もし実行した場合、以下のようなエラーが出る。
Can't vivify reference at tmp.pl line 16.