ジェネリックメソッド
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 66/110。
クラスがジェネリックになれるのと同様に、個別のメソッドも独自の型パラメータを持つことができます。これは、クラス全体をジェネリックにすることなく、柔軟なメソッドが必要な場合に便利です。
ジェネリックメソッドは、戻り値の型の前に型パラメータを宣言します:
T findFirst<T>(List<T> items) {
return items.first;
}
void main() {
var firstNumber = findFirst<int>([1, 2, 3]);
var firstWord = findFirst<String>(['hello', 'world']);
print(firstNumber); // 1
print(firstWord); // hello
}Dartは多くの場合、引数から型を推論できるため、常に明示的に指定する必要はありません。
var result = findFirst([10, 20, 30]); // Dartはintを推論しますジェネリックメソッドは、特定の操作のみに型の柔軟性が必要な場合に、クラス内で特に役立ちます:
class Printer {
void printItem<T>(T item) {
print('Printing: $item');
}
List<T> duplicate<T>(T item, int count) {
return List.filled(count, item);
}
}
void main() {
var printer = Printer();
printer.printItem<String>('Hello');
printer.printItem(42); // 型は int と推論されます
var copies = printer.duplicate('Hi', 3);
print(copies); // [Hi, Hi, Hi]
}ジェネリックメソッドを使用すると、メソッドレベルで型安全性をきめ細かく制御できるため、クラスをシンプルに保ちつつ、コンパイル時の型チェックの恩恵を受けることができます。
チャレンジ
簡単ジェネリックメソッドの威力を示すデータ変換ユーティリティを構築しましょう。クラス全体をジェネリックにすることなく、柔軟性を持たせるために、あらゆる型で動作するメソッドを持つ Transformer クラスを作成します。
コードを2つのファイルに整理します:
transformer.dart: 以下のジェネリックメソッドを持つTransformerクラスを作成します:T getFirst<T>(List<T> items)- リストから最初の要素を返しますT getLast<T>(List<T> items)- リストから最後の要素を返しますList<T> repeat<T>(T item, int times)- 指定された回数だけアイテムを繰り返したリストを作成しますvoid printPair<A, B>(A first, B second)- 2つの値をPair: [first] and [second]の形式で出力します
main.dart: トランスフォーマーファイルをインポートし、各ジェネリックメソッドを異なる型で実演します:Transformerインスタンスを作成します[10, 20, 30]に対してgetFirstを使用し、結果を出力します['apple', 'banana', 'cherry']に対してgetFirstを使用し、結果を出力します[1.5, 2.5, 3.5]に対してgetLastを使用し、結果を出力しますrepeatを使用して'Hi'を4回繰り返したリストを作成し、結果を出力しますrepeatを使用して7を3回繰り返したリストを作成し、結果を出力します'Name'と42を指定してprintPairを使用します100とtrueを指定してprintPairを使用します
各メソッドが独自の型パラメータを宣言することで、同じ Transformer オブジェクトが整数、文字列、double、ブール値のすべてに対して、完全な型安全性を保ちながら動作することに注目してください。printPair メソッドは、単一のメソッドで2つの型パラメータを使用する方法を示しています。
期待される出力:
10
apple
3.5
[Hi, Hi, Hi, Hi]
[7, 7, 7]
Pair: Name and 42
Pair: 100 and trueチートシート
ジェネリックメソッドは、戻り値の型の前に型パラメータを宣言します。これにより、クラス全体をジェネリックにすることなく、個々のメソッドに柔軟性を持たせることができます:
T findFirst<T>(List<T> items) {
return items.first;
}Dartは引数から型を推論できるため、明示的な型の指定は任意です:
var result = findFirst([10, 20, 30]); // Dartはintを推論しますジェネリックメソッドは、非ジェネリッククラスの中でも使用できます:
class Printer {
void printItem<T>(T item) {
print('Printing: $item');
}
List<T> duplicate<T>(T item, int count) {
return List.filled(count, item);
}
}メソッドは複数の型パラメータを宣言できます:
void printPair<A, B>(A first, B second) {
print('Pair: $first and $second');
}自分で試してみよう
import 'transformer.dart';
void main() {
// Transformer インスタンスを作成する
var transformer = Transformer();
// TODO: [10, 20, 30] に対して getFirst を使用し、その結果を表示する
// TODO: ['apple', 'banana', 'cherry'] に対して getFirst を使用し、その結果を表示する
// TODO: [1.5, 2.5, 3.5] に対して getLast を使用し、その結果を表示する
// TODO: repeat を使用して 'Hi' を4回繰り返したリストを作成し、それを表示する
// TODO: repeat を使用して 7 を3回繰り返したリストを作成し、それを表示する
// TODO: 'Name' と 42 を指定して printPair を使用する
// TODO: 100 と true を指定して printPair を使用する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ