Perlでは、ネストされた構造(例えば、配列のハッシュ、ハッシュの配列)のディープコピーを行うために、単純な代入や標準の関数(@b = @a, %b = %a, $clone = $orig)を使用することはできません。このような操作は、単なるシャローコピーを作成します:ネストされたオブジェクトは依然として同じメモリ領域を参照します。
ディープコピーを行うためには、以下の方法を使用します:
Storableモジュール:use Storable 'dclone'; my $deep_copy = dclone($structure);
Cloneモジュール:同様の使用法。重要なのは、構造内のリンクを含む、すべてのネストレベルがコピーされるということです。
複雑なデータ構造を単純に代入した場合、ネストされた要素はコピーされるのでしょうか?
回答: いいえ、コピーされるのは上位レベルのみです。内部の配列やハッシュはオリジナルとコピーの間で共有されたままです。
my $orig = { a => [1,2,3], b => { x => 7 } }; my $copy = $orig; $copy->{a}[0] = 99; # $orig->{a}[0] も99になります!
ディープクローンを使用することで、完全に独立したコピーを得ることができます。
ストーリー 1
REST APIアプリケーションで、異なるクライアントのリクエストを通常の参照の代入でクローンしました。その結果、一人のクライアントの応答の変更がすぐに他のすべてに反映されました—なぜなら、みんなが同じネストされたデータ構造を使っていたからです。
ストーリー 2
複雑な配列構造のデータをアグリゲートする際に、push(push @new, @old)を使用してコピーしましたが、ネストされたレベルを忘れていました。内部のハッシュをランダムに変更したことで、すべてのアグリゲートのデータが壊れ、バグは長い間特定できませんでした。
ストーリー 3
ログを処理するためにスクリプト内でCloneを使って構造を複製しましたが、特別な「マジック」オブジェクトフィールドを考慮しなかったため、必要なメソッド/属性を失いました。その結果、機能が無効になり、エラーは本番環境でのみ再現されました。