配列のコピーに注意!

皆さん、これは周知しないといけない事案が発生してしまいました!!

皆さん、こんにちは。K.Y.(HN Rerurate_514)です。

今回の記事は最近私がぶち当たった問題について説明していこうかと思います。

実際に起きたこと

私はFlutter(Dart)で配列について扱っていました。(実際はListですが)

このとき、次のようなコードを書きました。

List<int> oldList = [1, 2, 3, 4, 5];
 
List<int> newList = oldList;
 
newList.add(6);

ここでは、newListにのみ値を追加しています。
oldListは変更なしです。

私が実際に書いていたコードでは、oldListnewListの中身が重要だったので確認のためにそれぞれの値を出力してみました。

oldList.forEach((int value) {
	print("old = $value");
});
 
print("-----------------------");
 
newList.forEach((int value) {
	print("new = $value");
});

しかし、出力結果はどちらも同じだったのです!

old = 1
old = 2
old = 3
old = 4
old = 5
old = 6
-----------------------
new = 1
new = 2
new = 3
new = 4
new = 5
new = 6

これがどういうことなのか、かなり苦しみましたが私の中で結論が出ました。
それは、配列やリストの代入は参照になるということです。

シャローコピーってなに

しかしながら、配列やListをコピーしたい場面もあるかと思います。
その際には、スプレッド演算子を使用します。
実際に使用してみると、

List<int> oldList = [1, 2, 3, 4, 5];
 
List<int> newList = [...oldList];
 
newList.add(6);

となります。

これを先ほどのコードで出力してみると、

old = 1
old = 2
old = 3
old = 4
old = 5
-----------------------
new = 1
new = 2
new = 3
new = 4
new = 5
new = 6

となり、配列のコピーができて、かつ参照もしていないという結果になりました!

ちなみにこの時のコピー方法をシャローコピー(浅いコピー)といいます。
しかしながら多次元配列の時は、このシャローコピーを使用することはできません。
その際には、ディープコピーを使用します。ここでは解説しません。

さいごに

なぜデフォルトで参照を渡すのがずっと疑問で調べていて、公式ドキュメントを読み漁ったのですが、わかりませんでした;;

Arrayとかのオブジェクト型はコピーするのが重いからだとかという話もありましたが、参考文献がなかったので信憑性がありませんでした。

なぜデフォルトで参照なのか知っている方いたら教えてください。