Perlは、可変長配列と連想配列(ハッシュ)でダイナミックデータ構造が歴史的に有名です。言語の初期バージョンから、配列のサイズを変更することが可能です(配列に要素を追加するpush/pop、最初に要素を追加するunshift/shift;ハッシュではキーの削除/追加)。この柔軟性はPerlのアーキテクチャに組み込まれており、メモリが自動的に管理され、コンテナもプログラマーの明示的な介入なしに拡大または縮小されます。
問題は、大規模な変更時に発生します:最適でない操作の順序は不要なメモリ再配分を引き起こす可能性があり、構造を操作する誤った手法(例えば、foreachで要素を削除しながら繰り返すと)によってバグを引き起こす可能性があります。
解決策は、組み込みのbulk操作(splice、delete)を使用するか、map/grepを使用して新しい構造を構築し、構造を巡回している間の操作を避けることです。
コード例(条件による一括削除):
# 配列から偶数インデックスの要素を削除する my @arr = (1..10); @arr = grep { $_ % 2 } @arr; # 奇数だけが残る # 一括追加 push @arr, (11, 13, 15); # ハッシュの場合 my %hash = (a => 1, b => 2, c => 3, d => 4); delete @hash{ grep { $hash{$_} % 2 == 0 } keys %hash }; # 偶数の値を削除
主な特徴:
for/foreachで巡回中に配列から要素を安全に削除できますか?
答え:いいえ、それは予期しない動作につながります — インデックスがシフトして、ループが要素をスキップします。フィルタリング(map/grep)を使用するか、spliceを用いて逆順で反復してください。
autovivificationは新しい入れ子構造の作成にどのように影響しますか?
答え:存在しない要素にアクセスする際、Perlは自動的に構造を作成し、時間を節約できますが、「空の」構造を作成するなどの予期しない副作用を引き起こす可能性があります。厳密なメモリ管理が必要な場合は、手動でこれを制御してください。
my %h; $h{newkey}{subkey} = 1; # Perlは自動的にサブハッシュを作成します!
ハッシュ内の既存の値を上書きするのは常に高速なプロセスですか?
答え:スカラーおよびほとんどのシンプルなタイプではそうですが、値が大きな構造または参照の場合、参照カウントのコストがかかる可能性があります。大きな構造は、リンクを上書きするよりも、その場で変更する方が良いです。
開発者がforeach内で配列から要素を削除した結果、一部のデータが配列に残り、ループが正しく機能しなくなります。
利点:
欠点:
@arr = grep { 条件 } @arrを使用してフィルタリングを行ったり、インデックスによる削除を配列の最後から行います。
利点:
欠点: