Dartツアー(6)ジェネリック
Flutterを始めてみましたが、コードはDart言語で書きます。という訳で、Dart言語のツアーを見て勉強しながら、自分用にメモをまとめてみました。今回はジェネリック(Generics)です。自分がプログラミングを始めた頃にはなかった概念なのでやや苦手というか。そんなわけで、本文はほとんど翻訳。サンプルは動かせるように手を入れています。
前回分は以下から。
ジェネリック
配列の基本型であるListのAPIドキュメントを見ると、この型は実際にはListであることがわかる。<…>の表記はListが一般型(またはパラメータ化された型)であることを示すもので、正式な型パラメータを持つ型である。慣習として、ほとんどの型変数はE、T、S、K、Vのような1文字の名前を持っている。
なぜジェネリックを使うのか?
ジェネリックは型安全性のために必要とされることが多いが、コードの実行を可能にするだけでなく、それ以上の利点がある。
- ジェネリックタイプを適切に指定することでより良いコードが生成される
- ジェネリックを使用することでコードの重複を減らすことができる
文字列だけを含むリストを作りたい場合は、List<String>(「文字列のリスト」と読み替え)と宣言する。そうすれば、あなたや仲間のプログラマー、そしてツールは、文字列でないものをリストに代入することがおそらく間違いであることを検出することができます。以下はその例です。
ジェネリックスを使用するもう一つの理由はコードの重複を減らすことです。ジェネリックスを使うと静的解析を利用しつつ、多くの型間で単一のインターフェースと実装を共有できる。例えば、あるオブジェクトをキャッシュするためのインターフェイスを作成したとする。このインターフェイスの文字列固有のバージョンが必要であることがわかったので、別のインターフェイスを作成する。後で、このインターフェイスを番号で指定できるようにしたい……と思ったことはありませんか?
ジェネリック型は、これらのインターフェースをすべて作成する手間を省く代わりに、型パラメータを受け取るインターフェースを1つ作ることができる。
このコードでは、Tは代用型である。これは、開発者が後で定義する型と考えることができる。
コレクションリテラルの使用
List、Set、Mapの各リテラルはパラメータ化できる。パラメータ化されたリテラルは、開き括弧の前に<type>(リストとセットの場合)または<keyType,valueType>(マップの場合)を追加する以外は、これまで見てきたリテラルと同じです。以下は、型付きリテラルの使用例です。
パラメータ化された型をコンストラクタで使う
コンストラクタを使用する際に 1 つ以上の型を指定するには、クラス名のすぐ後にある角括弧 (<…>) に型を記述する。たとえば、以下のコードでは、整数のキーとView型の値を持つマップを作成する。
ジェネリックコレクションとそれに含まれる型
Dartのジェネリック型は具体化されると、実行時にその型情報を持ち運びます。例えば、コレクションの型をテストすることができます。
注:これに対し、Javaのジェネリックでは、ジェネリック型のパラメータを実行時に削除する「消去法」が採用されている。Javaでは、あるオブジェクトがListであるかどうかはテストできるが、List<String>であるかどうかはテストできない。
パラメータ化された型の制限
ジェネリック型を実装する際、引数として提供できる型を制限し、引数が特定の型のサブタイプでなければならないようにしたい場合がある。これは extends を使って行うことができる。
一般的な使用例としては、(デフォルトのObject?ではなく)Objectのサブタイプにすることで、ある型を確実に非Nullにできるようにすることが挙げられる。
extends は Object 以外の型にも使用できる。以下は、SomeBaseClass を拡張して、SomeBaseClass のメンバを T 型のオブジェクトで呼び出せるようにした例です。
ジェネリックメソッドの使用
当初、Dartのジェネリックサポートはクラスに限定されていた。ジェネリックメソッドと呼ばれる新しい構文では、メソッドや関数での型引数が可能です。
ここでは、最初の汎用型パラメータ()によって、型引数Tをいくつかの場所で使用することができる。
- 関数の戻り値の型(T)にある
- 引数の型(List)に含まれる
- ローカル変数の型(T tmp)に含まれる
次回
次回はライブラリと可視性、および、非同期サポートです。
ディスカッション
コメント一覧
まだ、コメントがありません