まずは問題のコードを見てみよう
void main() {
List before = [1, 2, 3];
List after = before;
after[0] = 50;
print(before); // [50, 2, 3]
print(after); // [50, 2, 3]
}
afterの中身しか変えていないのに、beforeリストの中身も変わってしまっている。
MapやSetの場合でも......
// Mapの場合
void main() {
Map before = {0: 'banana', 1: 'strawberry', 2: 'grape'};
Map after = before;
after[1] = 'pineapple';
print(before); // {0: banana, 1: pineapple, 2: grape}
print(after); // {0: banana, 1: pineapple, 2: grape}
}
// Setの場合
void main() {
Set before = {1, 2, 3};
Set after = before;
after.add(50);
print(before); // {1, 2, 3, 50}
print(after); // {1, 2, 3, 50}
}
Listと同様に、参照元のbeforeが勝手に変わってしまう。
原因
dartにおいて、元のオブジェクトを参照して作られたListやMapなどは同じアドレスを持っているためである。
上のコードを使って言うと、before = afterが常に成り立つ状態になっていると言える。
この一連の動作はdartだけではなく、他の主要なプログラミング言語でも発生するようだ......
より詳しく知りたい方はこちらの記事に目を通してみるといいかも。
値渡し・共有渡し・参照渡しを最小の例(5行)で端的に理解する
解決方法
Listどうしを=で結ぶのではなく、別アドレスのListを作成してあげると解決する。書き方は複数あるが、実行結果は全て同じ。
// toListメソッドを用いる
void main() {
List before = [1, 2, 3];
List after = before.toList(); // beforeを元に別のアドレスのリストを作成
after[0] = 50;
print(before); // [1, 2, 3]
print(after); // [50, 2, 3]
}
// addAllメソッドを用いる
void main() {
List before = [1, 2, 3];
List after = [];
after.addAll(before);
after[0] = 50;
print(before); // [1, 2, 3]
print(after); // [50, 2, 3]
}
// スプレッド演算子(...)を使う
void main() {
List before = [1, 2, 3];
List after = [...before];
after[0] = 50;
print(before); // [1, 2, 3]
print(after); // [50, 2, 3]
}
補足
この参照元が変わってしまう問題はクラスのインスタンスでも発生する。
そちらについては【Dart】オブジェクトをコピーするcopyWithの基本の記事の通りにすれば解決したので参考までに。