Developer

【初心者Unity】値渡しと参照渡し
2021.11.20
Lv1

【初心者Unity】値渡しと参照渡し

1.はじめに

本記事では、C#における値渡し参照渡しの違いについて解説していきます。
ゲーム制作には直接関わることの少ない話ですが、Unityが提供する一部の機能を理解する上で手助けとなる知識です。
また、上手く使いこなせばゲームのパフォーマンス向上も望めます。

Unity上で動作するサンプルコードも載せていますので、是非一緒に手を動かして確認してみてください!

2.値渡しとは

値渡しとは、引数に対して変数が保持している値を渡す方式です。
早速ですが、サンプルコードを見てみましょう。

void Start()
{
    int num = 1;
    Plus10(num);
}
// プラス10した値をコンソールに出力するメソッド
void Plus10(int arg)
{
    arg += 10;
    Debug.Log(arg);
}

実行した結果、コンソールには何が表示されるでしょうか?

答え
11

では続いて、次のサンプルコードではどうでしょう。

void Start()
{
    int num = 1;
    Plus10(num);
    Debug.Log(num); // 追加
}
// プラス10した値をコンソールに出力するメソッド
void Plus10(int arg)
{
    arg += 10;
    Debug.Log(arg);
}

実行した結果、コンソールには何が表示されるでしょうか?

答え
11
1

合っていましたか?
基本的な動作ですが、解説していきます。

今回、Startメソッド内で Plus10メソッドを呼び出しています。
その際、引数にはStartメソッド内で宣言した変数numを渡しています。

void Start()
{
    int num = 1;
    Plus10(num);
}

Plus10メソッド内では、引数に渡された値をプラス10してコンソールに出力しています。
その際、Startメソッド内ではnumという変数名だった値が、argという変数名で扱われています。

// プラス10した値をコンソールに出力するメソッド
void Plus10(int arg)
{
    arg += 10;
    Debug.Log(arg);
}

この時、numからargへは値のコピーが行われています。

図の通り、numとargにはメモリ上で別々の領域が割り当てられています。
引数にnumを渡すという行為は、numという領域の中身(ここでは1)を渡す、ということを意味しているのです。

2つ目のサンプルでは、Plus10メソッドを実行した後にnumの値を出力していますが、宣言時と変わらない1が出力されました。
これは、プラス10されたのが、numに保持されている1ではなく、argに保持されている1だからです。

このように、値渡しでは変数が保持する値のコピーを行うため、メソッド内の処理は呼び出し元の変数に影響を与えません

3.参照渡しとは

参照渡しとは、引数に対して変数が表す領域への参照を渡す方式です。
こちらもサンプルコードを見てみましょう。
参照渡しをする場合は、呼び出し元・呼び出し先双方で引数にrefを付けます。

void Start()
{
    int num = 1;
    Plus10(ref num);
}
// プラス10した値をコンソールに出力するメソッド
void Plus10(ref int arg)
{
    arg += 10;
    Debug.Log(arg);
}

実行した結果、コンソールには何が表示されるでしょうか?

答え
11

続いて、次のサンプルコードではどうでしょう。

void Start()
{
    int num = 1;
    Plus10(ref num);
    Debug.Log(num); // 追加
}
// プラス10した値をコンソールに出力するメソッド
void Plus10(ref int arg)
{
    arg += 10;
    Debug.Log(arg);
}

実行した結果、コンソールには何が表示されるでしょうか?

答え
11
11

合っていましたか?
値渡しとは違う結果になりましたね。

参照渡しの場合、numからargへは変数が表す領域への参照が渡されます。
変数が表す領域への参照、とは何でしょうか?
ここで言う参照は、場所という言葉で置き換えていただいて構いません。
つまり、変数が表す領域の場所と言い換えることができます。
では、場所とは具体的に何なのでしょうか?

メモリには、アドレスと呼ばれる、場所を表す数字が割り振られています。
図では、numが表す領域には100番地というアドレスが割り振られています。

参照渡しで渡す場所とは、この100番地という情報です。
この結果、argも100番地を表す変数として認識されるようになります。
つまり、100番地という領域に対して、numという変数からもargという変数からもアクセスできるようになる訳です。
(変数領域に別名を付ける、と表現されることもあります。)

そのため、2つ目のサンプルでは、argに対してプラス10した結果がnumにも反映されているのでした。

このように、参照渡しでは呼び出し元と呼び出し先が同じ変数領域を表すようになるため、メソッド内の処理が呼び出し元の変数に影響を与えるようになります。

4.おわりに

値渡しと参照渡しの違いについて解説しました。
文字だけでは中々理解が難しい内容ですので、メモリのイメージ図を自分でも持てるようにしてください。

Unityでの使用場面はこちらの記事をご覧ください。
【初心者Unity】Raycastのoutって何?outパラメーター修飾子について解説

最後に、参照渡しについては、参照型変数の値渡しと混同されることが多いので、ひとつ例題を出しておきます。
参照型変数の場合も値型変数と動作は同じです。
値を渡すのか、領域を渡すのか。しっかりと区別を付けられるようにしましょう。

void Start()
{
    string name = "tanaka";
    Replace1(name);
    Debug.Log(name);
    Replace2(ref name);
    Debug.Log(name);
}
void Replace1(string arg)
{
    arg = "suzuki";
    Debug.Log(arg);
}
void Replace2(ref string arg)
{
    arg = "sato";
    Debug.Log(arg);
}

実行した結果、コンソールには何が表示されるでしょうか?

答え
suzuki
tanaka
sato
sato

 

連載目次リンク

「初心者のための」Unityゲーム制作 目次
 

Unity実践編 - 目次リンク

実践Unityゲームプログラミング 連載目次