GameMaker 日本語掲示板

配列を引数として関数に渡すことについて

4 コメント
views
16 フォロー

配列は関数に渡すと参照で渡される。

myarray = ["dog", "cat", "flower"];

function show_array(_array) {
  show_debug_message(_array[1]);
}

show_array(myarray);

cat と出力される。
しかし渡した配列を変更しようとすると、関数内でコピーが作られる。returnで元の配列myarrayに返してやらないと、myarrayは更新されない。下記を実行するとどうなるか。

myarray = ["dog", "cat", "flower"];

function rewrite_array(_array) {
	show_debug_message("(1) _array[1]="+string(_array[1]));
	_array[1] = "food";
	show_debug_message("(2) _array[1]="+string(_array[1]));
}

rewrite_array(myarray);

show_debug_message("(3) myarray[1]="+string(myarray[1]));

(1) _array[1]=cat
(2) _array[1]=food
(3) myarray[1]=cat
と出力される。元のmyarrayは変更されていない。

そこで、関数内で配列アクセッサ@を使う。これで関数内から配列を直接更新できる

myarray = ["dog", "cat", "flower"];

function rewrite_array(_array) {
	show_debug_message("(1) _array[1]="+string(_array[1]));
	_array[@ 1] = "food";
	show_debug_message("(2) _array[1]="+string(_array[1]));
}

rewrite_array(myarray);

show_debug_message("(3) myarray[1]="+string(myarray[1]));

結果。
(1) _array[1]=cat
(2) _array[1]=food
(3) myarray[1]=food
元の配列myarrayが変更された。

コピーを作り(自動で作られる)、それを変更し、元の配列に返して更新する というのは手間がかかる。オーバーヘッドも生じる。
なので@を使って直接変更すればいいよという話でした。

asa
作成: 2021/12/23 (木) 16:56:41
最終更新: 2021/12/23 (木) 16:59:36
通報 ...
1
生高橋 2021/12/23 (木) 18:10:49

array = array2;
みたいな代入だとコピーされるんですかね?

2
asa 2021/12/23 (木) 20:03:36 修正

array2 = array1
やってみました。
関数に渡したときと同じことが起きてるように見えます。
つまり、array2 = array1でarray2はarray1の参照になり、array2を変更しようとした時点でコピーされ別の配列になる。

array1 = ["dog", "cat", "fox"];
array2 = array1;

show_debug_message("(1) array1 = "+string(array1));
show_debug_message("(1) array2 = "+string(array2));

array2[1] = "123"; // ★1

show_debug_message("(2) array1 = "+string(array1));
show_debug_message("(2) array2 = "+string(array2));

結果
(1) array1 = [ "dog","cat","flower" ]
(1) array2 = [ "dog","cat","flower" ]
(2) array1 = [ "dog","cat","flower" ]
(2) array2 = [ "dog","123","flower" ]
array2だけが変更されている。ということはコピーされていてarray1とarray2は別の配列になっていると見ることができる。

★1の部分を array2[@ 1] = "123"; にすると、 
結果
(1) array1 = [ "dog","cat","flower" ]
(1) array2 = [ "dog","cat","flower" ]
(2) array1 = [ "dog","123","flower" ]
(2) array2 = [ "dog","123","flower" ]
array1とarray2が両方変わっている
array2はarray1の参照のままであり、array2[@ 1]でarray1[1]を直接変更したと考えられる。

★1の部分を array1[1] = "123"; にすると、
結果
(1) array1 = [ "dog","cat","flower" ]
(1) array2 = [ "dog","cat","flower" ]
(2) array1 = [ "dog","123","flower" ]
(2) array2 = [ "dog","123","flower" ]
array1とarray2が両方変更されている
array2はarray1の参照であるからarray1の内容を示していると考えられる。

3
生高橋 2021/12/23 (木) 20:58:21

なるほど

4
asa 2022/02/25 (金) 11:12:25 修正

この辺の仕様が、Version 2022.2.0.614 で変更されるそうです。
詳しくはリリースノートを。
https://gms.yoyogames.com/ReleaseNotes.html

ブログにも情報ありました。
https://www.yoyogames.com/en/blog/release-2022-2
(記事終盤のCOPY ON WRITE OPTIONの箇所)