Menu
Coddy logo textTech

ジェネリックメソッド

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]
}

ジェネリックメソッドを使用すると、メソッドレベルで型安全性をきめ細かく制御できるため、クラスをシンプルに保ちつつ、コンパイル時の型チェックの恩恵を受けることができます。

challenge icon

チャレンジ

簡単

ジェネリックメソッドの威力を示すデータ変換ユーティリティを構築しましょう。クラス全体をジェネリックにすることなく、柔軟性を持たせるために、あらゆる型で動作するメソッドを持つ 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 を使用して 73 回繰り返したリストを作成し、結果を出力します
    • 'Name'42 を指定して printPair を使用します
    • 100true を指定して 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 を使用する
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン