言語編 |
基本的な配列の型であるListのAPIドキュメンテーションを見ると、そこにはその型は実際はList<E>であることが判る。<…>記述はListは総称(或いはパラメタ化された)型、即ち正式の型パラメタたちを持っている型であることを示す。総称型の殆どの型パラメタは慣行的に E, T, S, K, 及び Vといった1文字の名前を持っている。
総称型はしばしば型安全性が求められるものの、単に自分のコードを走れるようにするということ以上の利点がある:
適切な総称型を指定することで生成されたコードがより良いものとなる
総称型を使うと重複したコードを減らすことができる
もしあるリストを文字列のみを含むようにしたいときは、List<String>(”文字列のリスト (list of string)”と読む)を宣言できる。そのほうが自分、同僚、そして自分のツールがそのリストに文字列でないものを代入しているのは多分ミスだと検出できる。以下はその例である:
|
総称型を使うもう一つの理由はコードの重複を減らすことである。総称型により、多くの型間で単一のインターフェイスと実装を共有できるようになる一方で、静的解析の利点が維持される。例えば、あるオブジェクトを捕捉するインターフェイスを作りたいとする:
|
このインターフェイスの文字列専用のバージョンが欲しくなったら、別のインターフェイスを書くことになる:
|
その後このインターフェイスの数値専用のバージョンが欲しくなった際・・・アイデアが浮かぶ筈である。
総称型がこれらすべてのインターフェイスたちを作るという問題から救ってくれる。そうしないで型パラメタを受け付ける単一のインターフェイスが作れる:
|
このコードの中でTは代行型(stand-in type)である。これは取りあえずある型として一時的に置いておくもので、デベロッパが後でそれを定義すればよい。
ListとMapのリテラルもパラメタ化できる。パラメタ化されたリテラルは、括弧を開く前に<type>(リストの時)または<keyType, valueType>(マップの時)を付加することを除いて既に見てきたリテラルと似ている。以下は型付けされたリテラルを使った例である:
|
コンストラクタを使う際はクラス名の直後に山形ブラケット(<...>)の中にその型を置く。例えば:
|
以下のコードは整数のキーとView型の値を持つマップを作っている:
|
Dartの総称型はJavaと違って具体化された総称型(reified generics)に対応している。即ち総称型のオブジェクトたちはそれらの型引数たちの情報を実行時に保持する。総称型のコンストラクタに型引数を渡すのはランタイムの操作である。例えば、あるコレクションの型をテストできる:
|
注意:これに比べJavaに於ける総称型は型削除(erasure)であり、これは総称型の型パラメタはランタイムで削除されることを意味する。Javaでは、あるオブジェクトがListかどうかをテストできるが、List<String>であるかはテストできない。
ある総称型を実装しようとする際、そのパラメタたちの型を制限したいことがあろう。extendsを使うとそれは可能である。
|
SomeBaseClassまたはそのサブクラスたちのどれかを総称引数として使うことはOKである:
|
総称型の引数がないことを指定することもOKである:
|
非SomeBaseClass型を指定するとエラーとなる:
|
当初Dartの総称型サポートはクラスたちに限られていた。総称型メソッド(generic methods)と呼ばれる新しい構文では、メソッドと関数での型引数を許している:
|
ここではfirst (<T>)上の総称型パラメタで、型引数Tを幾つかの場所で使えるようになる:
この関数の戻りの型(T)
引数の型の中(List<T>)
ローカル変数の中(T tmp)
総称型に関する更なる情報はUsing Generic Methodsにある。