トーフメモ

主にゲーム制作

GOTO文は使いよう【UnityC#】

f:id:tofgame:20190528160203p:plain

そもそもGOTO文とは

ラベルを記述した場所に処理を飛ばすことができる記法です。

private IEnumerator Start () {
    A:
    Debug.Log("ループするよ");
    yield return new WaitForEndOfFrame();
    goto A;
}

上みたいなのだとwhile(true)と同じような動作をします。
これだとどこに飛ぶかがわかりにくい・・・
きれいに記述されたコードが光属性なら、GOTO文をたくさん使ったコードは闇属性だと思います(?)。
なんとなく嫌なイメージが先行しているGOTO文ですが、GOTO文について僕は何もしらなかったので、詳しく調べてみました。

なぜ忌嫌われるのか

スパゲッティコードを量産できてしまう」点にあると思います。

簡単☆スパゲッティソース☆

private IEnumerator Start () {
    while(true) {
        START:
        int num = Random.Range(0,4);

        switch(num) {
            case 0:
            Debug.Log("run 0 to 2");
            yield return new WaitForEndOfFrame();
            goto case 2;

            case 1:
            Debug.Log("run 1 to 4");
            yield return new WaitForEndOfFrame();
            goto case 4;

            case 2:
            Debug.Log("run 2 to 1");
            yield return new WaitForEndOfFrame();
            goto case 1;

            case 3:
            Debug.Log("run 3 to START");
            yield return new WaitForEndOfFrame();
            goto START;

            case 4:
            Debug.Log("run 4 to end");
            yield return new WaitForEndOfFrame();
            break;
        }

        Debug.Log("end");
        break;
    }
}

何を書いているのか僕にもわかりません。
スパゲッティがかなり的を射た比喩なのが実感できます。

Go To Statement Considered Harmful

「Go To Statement Considered Harmful」という名前の論文も出るほどにgotoについては議論されています。
この論文に、「The unbridled use of the go to statement has an immediate consequence that it becomes
terribly hard to find a meaningful set of coordinates in which to describe the process progress.
Usually, people take into account as well the values of some well chosen variables, but this is out of the question because it is relative to the progress that the meaning of these values is to be understood!」と書かれています。
意味の通るようなプログラムの進行にしにくくなるので、goto文の乱用はよくないそうです。
(論文リンク)http://www.gdv.informatik.uni-frankfurt.de/lehre/ws2005/PRG1/Readings/W4-Go-To-Statement-Considered-Harmful.pdf


どこで使うといいのか

多重ループ(ネストループ)から抜ける

forループなどで条件に応じてループを抜ける、といった書き方はbreakを使えばできますが、ループが2重3重に重なると、breakも2重3重に重ねなければいけません。
しかし、goto文を使いループ外にジャンプすることでループから抜けられます。(関数化してreturnしても同じようにできますが・・・)

private void Start () {
    for(int i = 0;i < 100;i++) {
        for(int j = 0;j < 100;j++) {
            for(int k = 0;k < 100;k++) {
                if(i * j * k >= 10000) {
                    goto END;
                }
            }
        }
    }

    END:;
}

おわりに

goto文を使わなくてもいい場面が多いので、めったに使うことはありませんが、goto文のこともたまには思い出してあげてください。

参考にしました

ufcpp.net
marycore.jp
marycore.jp