Menu
Coddy logo textTech

Future と async/await

CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 76/110。

実際のアプリケーションでは、サーバーからのデータの取得、ファイルの読み込み、ユーザー入力の待機など、多くの操作に時間がかかります。DartはこれらをFutureで処理します。これは、将来のある時点で利用可能になる値を表します。

Future はプロミス(約束)のようなものです:「準備ができたら結果を渡します」。Future.delayed() を使用して、時間のかかる操作をシミュレートすることで作成できます:

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Futureの結果を扱うには、asyncawaitを使用します。関数をasyncとしてマークし、awaitを使用してFutureが完了するまで実行を一時停止します:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

await なしでは、実際の文字列ではなく Future<String> を受け取ることになります。await キーワードは Future をアンラップし、その中の値を返します。await を使用する関数は async とマークされている必要があり、自動的に Future を返すことに注意してください。

async関数から直接値を返すこともできます。Dartはそれらを自動的にFutureでラップします:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // 自動的にFuture<int>でラップされます
}
challenge icon

チャレンジ

簡単

異なる都市の気象データを取得することをシミュレートする気象サービスを構築しましょう!完了までに時間がかかる操作を処理するために、Futureasync、および await を使用する練習をします。

コードを2つのファイルに整理します:

  • weather_service.dart: 気象情報の取得をシミュレートする WeatherService クラスを作成します。クラスには以下を含める必要があります:
    • Future<int> を返すメソッド fetchTemperature(String city)。ネットワーク遅延をシミュレートするために、100ミリ秒の期間で Future.delayed() を使用します。このメソッドは、都市名に基づいた温度を返す必要があります。都市名の長さに3を掛けた値を返してください。
    • Future<String> を返すメソッド fetchCondition(String city)。100ミリ秒の遅延で Future.delayed() を使用します。都市名の文字数が偶数の場合は 'Sunny' を返し、そうでない場合は 'Cloudy' を返します。
    • Future<String> を返す async メソッド getFullReport(String city)。このメソッドは fetchTemperaturefetchCondition の両方を await し、フォーマットされた文字列 '[city]: [temperature]C, [condition]' を返す必要があります。
  • main.dart: 気象サービスをインポートし、非同期操作がどのように機能するかを示します。main 関数は async である必要があり、以下の処理を行います:
    • WeatherService インスタンスを作成する
    • 'Fetching weather data...' とプリントする
    • 'Paris' のフルレポートを await してプリントする
    • 'Tokyo' のフルレポートを await してプリントする
    • 'London' のフルレポートを await してプリントする
    • 'Done!' とプリントする

getFullReport の各呼び出しが、結合された結果を返す前に、温度とコンディションの両方が取得されるのをどのように待機するかに注目してください。await キーワードは、各 Future が完了するまで実行を一時停止します!

期待される出力:

Fetching weather data...
Paris: 15C, Cloudy
Tokyo: 15C, Cloudy
London: 18C, Sunny
Done!

チートシート

Future は、将来利用可能になる値を表します。データの取得やファイルの読み込みなど、時間のかかる操作に使用されます。

Future.delayed() を使用して Future を作成します:

Future<String> fetchUserName() {
  return Future.delayed(
    Duration(seconds: 1),
    () => 'Alice',
  );
}

Future を扱うには asyncawait を使用します。関数を async としてマークし、await を使用して Future が完了するまで実行を一時停止します:

Future<void> main() async {
  print('Fetching user...');
  String name = await fetchUserName();
  print('Hello, $name!');
}

await キーワードは Future をアンラップし、実際の値を取得します。これがないと、文字列ではなく Future<String> を受け取ることになります。

await を使用する関数はすべて async とマークする必要があり、自動的に Future を返します。

async 関数からの戻り値は、自動的に Future でラップされます:

Future<int> calculateTotal() async {
  var a = await fetchNumber();
  var b = await fetchNumber();
  return a + b;  // 自動的に Future<int> でラップされます
}

自分で試してみよう

import 'weather_service.dart';

Future<void> main() async {
  // TODO: WeatherService インスタンスを作成する
  
  // TODO: 'Fetching weather data...' と出力する
  
  // TODO: 'Paris' の完全なレポートを await して出力する
  
  // TODO: 'Tokyo' の完全なレポートを await して出力する
  
  // TODO: 'London' の完全なレポートを await して出力する
  
  // TODO: 'Done!' と出力する
}
quiz icon腕試し

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

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