Developer

【初心者Unity】Raycastのoutって何?outパラメーター修飾子について解説
2021.11.20
Lv1

【初心者Unity】Raycastのoutって何?outパラメーター修飾子について解説

1.はじめに

本記事では、outパラメーター修飾子について解説します。
…outパラメーター修飾子、と聞いてもいまいちピンと来ないかも知れませんね。

皆さんの身近な例で言うと、Raycastの引数に書かれているoutがoutパラメーター修飾子です。

if(Physics.Raycast(ray, out hit))
{
    ⋮
}

このように、Unityが提供する一部の機能で使われていますが、意味はよく分かっていないまま定型文のように書いている、という方も多くいらっしゃるのではないでしょうか。

今回の内容で、直接ゲーム制作に関わる部分は少ないとは思います。
ですが、上で挙げたRaycast等、一部の機能の動作を理解する上では避けられない話になりますので、しっかりと理解しておくことをお勧めします。

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

2.outパラメーター修飾子とは

outパラメーター修飾子は、参照渡しを行うための修飾子です。
参照渡しについてはこちらの記事をご覧ください。
【初心者Unity】値渡しと参照渡し

参照渡しを行うための修飾子にはoutの他、ref、inが用意されています。

初期化 メソッド内での上書き 用途
ref 必須 可能 メソッド内外の双方向でデータの受け渡しを行う
out 不要 必須 メソッド内からメソッド外へデータを渡す
in 必須 不可 データ量の多い値型の変数をメソッドへ渡す

3.outパラメーター修飾子の使い方

outパラメーター修飾子は、メソッド内からメソッド外へデータを渡す用途で使用されます。
こう聞くと、メソッドの戻り値との違いがわからないかもしれませんね。
実際には、outパラメーター修飾子は戻り値の補助的な役割で使われることが多いです。

次のサンプルコードをご覧ください。

void Start()
{
    int diff;
    if (GreaterThan100(120, out diff))
    {
        Debug.Log(diff); // 20 が出力される
    }
}
bool GreaterThan100(int num, out int diff)
{
    diff = num - 100;
    return 100 < num;
}

GreaterThan100メソッドは、

  • 100より大きいかどうか(bool)
  • 100との差(int)

の2種類の結果を返すメソッドとして定義されています。
ですが、戻り値のみで複数の型の値を返すには工夫が必要です(詳しくは後述)。
ここを補うのがoutパラメーター修飾子の役割となります。

・100より大きいかどうか(bool)
これは戻り値としてStartメソッドに返しています。
戻り値の型はbool型ですし、returnしているものはまさにそれです。
・100との差(int)
こちらは、diffという変数に計算結果を格納しています(11行目)。
ここで、diffは参照渡しされる引数として定義されているので、Startメソッドの変数diffにも変更が反映されます。
そのため、実質、計算結果を返すことができています。

このように、outパラメーター修飾子を使うことで、複数の型の値を同時に返すことができるようになります。

なお、C# 7.0以降のバージョンを使用している場合は、次のように書き換えることもできます。

void Start()
{
    // int diff;
    if (GreaterThan100(120, out int diff)) // 引数に渡すタイミングで宣言
    {
        Debug.Log(diff);
    }
}
bool GreaterThan100(int num, out int diff)
{
    diff = num - 100;
    return 100 < num;
}

4.refパラメーター修飾子との違い

先ほどの例は、refパラメーター修飾子で記述することもできます。

void Start()
{
    int diff = 0;
    if (GreaterThan100(120, ref diff))
    {
        Debug.Log(diff);
    }
}
bool GreaterThan100(int num, ref int diff)
{
    diff = num - 100;
    return 100 < num;
}

refパラメーター修飾子とoutパラメーター修飾子の違いは以下の2点です。

  • refを使用する場合は、変数の初期化が必要(3行目)
  • outを使用する場合は、メソッド内での代入処理が必須

このような違いがあるとは言え、使用感はあまり変わりません。

強いて言えば、

  • refは元の値に何らかの操作を加えて返す
  • outは完全に新しい値で上書きする

という用途の違いがあるため、メソッドの利用者もそのような動作を期待します。
メソッドの役割を利用者に伝えるという意味でも、用途に応じて使い分けることをお勧めします。

5.outパラメーター修飾子の使用例

outパラメーター修飾子を使用しているメソッドをいくつかご紹介します。

Physics.Raycast
1つ目は、冒頭でも触れたPhysics.Raycastメソッドです。
メソッドの詳細はこちらの記事をご参照ください。
【初心者Unity】Raycastの基本的な使い方(オブジェクトをクリックで取得)

void Start()
{
    Vector3 origin = new Vector3(0, 0, 0);
    Ray ray = new Ray(origin, Vector3.forward);
    if (Physics.Raycast(ray, out RaycastHit hit))
    {
        Debug.Log(hit.collider.gameObject.name);
    }
}

戻り値としてRayと衝突したか否かをbool型で返す他、引数hitに衝突した相手オブジェクトの情報を格納します。
後者でoutパラメーター修飾子が使用されていますね。

int.TryParse
2つ目は、int.TryParseメソッドです。
文字列をint型に変換する機能がメインですが、

  • 第1引数の文字列をint型に変換できるか否か(bool)
  • 第1引数の文字列をint型に変換した値

の2つの結果を得ることができます。
前者を戻り値で、後者をoutパラメーター修飾子で、呼び出し元のメソッドに返しています。

void Start()
{
    if (int.TryParse("123", out int result))
    {
        Debug.Log(result + 1); // 124 が出力される
    }
}

6.outパラメーター修飾子を使わない書き方

3.outパラメーター修飾子の使い方で、戻り値のみで複数の型の値を返すには工夫が必要、と書きました。
戻り値のみで同じことを実装する手段としては、

  • クラスを定義する
  • 構造体を定義する
  • タプルを使用する

といった方法があります。

このうちの3つ目、タプルはC# 7.0から登場した新機能で、まさに、戻り値のみで複数の型の値を返すために実装された、と言われている機能になります。
試しに、GreaterThan100メソッドをタプルを使って記述してみます。

void Start()
{
    (bool judge, int diff) = GreaterThan100(120);
    if (judge)
    {
        Debug.Log(diff);
    }
}
(bool judge, int diff) GreaterThan100(int num)
{

    return (100 < num, num - 100);
}

書き方は少し癖がありますが、見事戻り値のみで実装ができています。

このタプルの登場によって、outパラメーター修飾子の優位性が失われているのが現状です。
参照渡しの実装は気を使うところが多いため、今後メソッドを自作する際には、outパラメーター修飾子ではなくタプルを使用することをお勧めします。

7.おわりに

outパラメーター修飾子について解説しました。
最後に述べたように、outパラメーター修飾子を使って新たな何かを生み出すという機会は少ないかも知れません。
ですが、昔からある機能ではoutパラメーター修飾子を使用したものも多く、それらを使用する上で内部のメカニズムを把握していた方が安全なコーディングとなるでしょう。

本記事がその理解の一助となれば幸いです。

 

連載目次リンク

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

Unity実践編 - 目次リンク

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