Tsuの雑記¯\_(ツ)_/¯

主に製作メモ・備忘録として使用。製作したアプリのリンクもあります。

【Unity】for 文を分解するよ【C#】

C#の for ステートメントを構成する3要素は,それぞれ独立させて管理する事が出来ます。

これを利用する事で,for ステートメントの挙動を引数によって変える事も可能になります。

本稿では,メソッド化→デリゲート化→パラメータ化という順番で御説明いたします。

(Unity 2018.3.0f2)


始めに

for ステートメントでは、指定されたブール式が true と評価される間、ステートメントまたはステートメント ブロックが実行されます。

つまりfor文とは,「条件が一致している間は繰り返す」という仕組みですね。

以下のような用法が,一般的と思われます。

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // -2から0未満まで1ずつ加算
        for (var i = -2; i < 0; i++)
        {
            // console に出力
            Debug.Log(i);
        }

        // 2から0まで2ずつ減算
        for (var i = 2; i >= 0; i -= 2)
        {
            // console に出力
            Debug.Log(i);
        }
    }
}

Console ウィンドウに整数値が出力されている画像
Console ウィンドウに出力された値

Microsoft の公式リファレンスでは,次のように定義されています。

for (initializer; condition; iterator)
    body

実は,3つのセクションはそれぞれメソッドとして独立させる事が出来ます。


各セクションのメソッド化

using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // カウント用整数
        int i;

        // カウント用整数を-2に
        void InitializerA() { i = -2; }
        // カウント用整数が0未満なら真
        bool ConditionA() { return i < 0; }
        // カウント用整数を1加算
        void IteratorA() { i++; }

        // 繰り返し処理
        for (InitializerA(); ConditionA(); IteratorA())
        {
            // console に出力
            Debug.Log(i);
        }

        // カウント用整数を2に
        void InitializerB() { i = 2; }
        // カウント用整数が0以上なら真
        bool ConditionB() { return i >= 0; }
        // カウント用整数を2減算
        void IteratorB() { i -= 2; }

        // 繰り返し処理
        for (InitializerB(); ConditionB(); IteratorB())
        {
            // console に出力
            Debug.Log(i);
        }
    }
}

メソッド化できるという事は,デリゲートにも出来ます。


各セクションのデリゲート化

using UnityEngine;
// Action, Func のため
using System;

public class NewBehaviourScript : MonoBehaviour
{
    void Start()
    {
        // カウント用整数
        var i = 0;

        // カウント用整数を-2に
        Action initializer = (() => { i = -2; });
        // カウント用整数が0未満なら真
        Func<bool> condition = (() => { return i < 0; });
        // カウント用整数を1加算
        Action iterator = (() => { i++; });

        // 繰り返し処理
        for (initializer(); condition(); iterator())
        {
            // console に出力
            Debug.Log(i);
        }

        // カウント用整数を2に
        initializer = (() => { i = 2; });
        // カウント用整数が0以上なら真
        condition = (() => { return i >= 0; });
        // カウント用整数を2減算
        iterator = (() => { i -= 2; });

        // 繰り返し処理
        for (initializer(); condition(); iterator())
        {
            // console に出力
            Debug.Log(i);
        }
    }
}

デリゲート化できるという事は,引数に設定する事も出来ます。


各セクションのパラメータ化

using UnityEngine;
// Action, Func のため
using System;

public class NewBehaviourScript : MonoBehaviour
{
    // カウント用整数
    int i;

    void Start()
    {
        // -2から0未満まで1ずつ加算
        Repeat(() => { i = -2; }, () => { return i < 0; }, () => { i++; });
        // 2から0まで2ずつ減算
        Repeat(() => { i = 2; }, () => { return i >= 0; }, () => { i -= 2; });
    }

    /// <summary>
    /// for ステートメントの各要素をパラメータに持つ繰り返しメソッド
    /// </summary>
    /// <param name="initializer">初期化</param>
    /// <param name="condition">ループ継続判定</param>
    /// <param name="iterator">ループ後処理</param>
    void Repeat(Action initializer, Func<bool> condition, Action iterator)
    {
        // 繰り返し処理
        for (initializer(); condition(); iterator())
        {
            // Console に出力
            Debug.Log(i);
        }
    }
}

これで,呼び出し元の引数によってfor文の挙動を変える事が出来ました。


終わりに

今回はfor文の中身が少ないために利点が伝わりにくいかもしれませんが,場合によっては活躍しそうです。

以上,forステートメントの分解でした。