はじめに
こんにちはsuzukiです。今回はGenericsの基本編です。例を交えて基本的な考え方をまとめました。
私は使う機会はそれなりにあるのですが、追加開発では初めから実装しないので書き方を忘れがちです。
今後の備忘として参考にできたらと思っています。
記事として少し長くなるため、2~3回でまとめさせていただく予定です。
Genericsとは
型をパラメーターとして受け取ることにより、その型に対応したクラスやメソッドを生成する機能です。
Genericsを使うことで型だけが異なり処理内容が同じクラスやメソッドを簡潔に書くことができます。
Genericsの例
今回は例としてSwapという処理をもとに考えていきます。
Genericsを使わない場合
例えば2つの整数の参照を入れ替えるという関数を記述すると下記のようになります。
1 2 3 4 5 6 7 8 9 | staticvoidSwapInt(ref inta,ref intb) { //tempIntにaを一時的に代入 inttempInt=a; //aにbを代入 a=b; //bにtempIntを代入 b=tempInt; } |
SwapIntを利用し整数の参照を入れ替えるコードを記述すると下記になります
1 2 3 4 5 | inta=5; intb=10; Swap(refa,refb); Debug.Log("a = "+a); Debug.Log("b = "+b); |
ログ出力結果
1 2 | a=10 b=5 |
整数だけを扱う関数であれば問題ないのですが、同じ処理を文字列や小数でも行いたい場合にそれぞれの関数を作成するのは大変です。またコード量が増えるので当然保守性が下がってしまいます。
Genericsを使う場合
SwapIntはintの型のみしか使えない関数でしたが、Genericsを使うと型をパラメーターとして受け取ることができます。
使い方は関数名の後ろに<>を追加し受け取る型パラメーター名を設定します。Genericsを使う時によく
また受け取ったTと同じ型で、a,bの参照とtempの型が設定されています。
1 2 3 4 5 6 7 8 9 10 | //型パラメーターとしてTを受け取る staticvoidSwap<T>(refTa,refTb) { //受け取った型のtempにaを代入 Ttemp=a; //aにbを代入 a=b; //bにtempを代入 b=temp; } |
Swapを利用するには関数名<型>(引数)のように呼び出しが可能です。
また、今回のように型パラメーターと引数の型が同じ場合<型>を簡略化することが可能です。
1 2 3 4 5 6 7 8 9 10 | inta=5; intb=10; //型パラメータを指定して関数の呼び出し Swap<int>(refa,refb); Debug.Log("a = "+a+" b = "+b); stringstr1="abc"; stringstr2="def"; //型パラメータは引数で明示的に与えれる場合は簡略化が可能 Swap(ref str1,ref str2); Debug.Log("str1 = "+str1+" str2 = "+str2); |
ログ出力結果
1 2 | a=10 b=5 str1=def str2=abc |
Genericを使うことにより、”同じ任意のクラスのaとbの参照先を入れ替える”という抽象的な関数にすることができました。SwapIntに比べ様々なクラスを引数に設定できるようになり便利になりました。
Genericsのメリット
またGenericsを使うメリットが大きい例として、コレクションクラスと呼ばれる配列のような複数の値をひとまとめにするクラスの処理を考えていきましょう。
例)配列で行いたい処理
- 中身がintだったら各要素の総和のintが返却される関数
- 中身がfloatだったら各要素の総和のfloatが返却される関数
- 中身がstringだったら各要素をつなげたstringが返却される関数
独自に行う場合foreachでそれぞれの要素(int,float,string)を+するという処理で実装可能です。しかしそれぞれ関数として定義するとコード量が多くなります。
またコレクションクラスとしても配列以外にも可変長配列などもあります。さらに総和以外の処理を追加することも考えられます。
上記をそれぞれ関数化するのではなく、Genericsを使い任意の型を格納し任意の種類のコレクションを扱えるコレクション操作関数を作成すれば、それぞれの関数を定義する必要がなくなるため、依存性も相関性も低い状態を作ることができます。
つまり雪だるま式に増えていくコードを書かなくても良くなります!
さいごに
今回は関数のGenericsを利用して説明させていただきました。他にもクラスを使う場合や制約条件の使い方等を次回にまとめさせていただきます。漫然と誰かが作ったGenericsを使うだけでなく、自分も途中からでも活用すべき内容はないか検討していきたいです。それではまた次回もよろしくお願いいたします。