Late変数
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 19/110。
lateキーワードは、非ヌル許容(non-nullable)変数が、すぐには代入されなくても、使用される前に初期化されることをDartに伝えます。これは、宣言時やコンストラクタでフィールドを初期化できないものの、アクセスされる前に必ず値を持つことが確実な場合に便利です。
class User {
late String username;
void initialize(String name) {
username = name;
}
void greet() {
print('Hello, $username!');
}
}
User user = User();
user.initialize('Alice');
user.greet(); // Hello, Alice!late がないと、Dart は username が初期化されていないと警告します。late 修飾子は、読み取る前に値を代入することを約束するものです。
late のもう一つの利点は、遅延初期化です。初期化子を持つ late 変数は、最初にアクセスされるまでその値を計算しません:
class Config {
late String settings = loadSettings();
String loadSettings() {
print('Loading...');
return 'default';
}
}
Config config = Config();
print('Config created');
print(config.settings); // ここで "Loading..." が出力され、その後に "default" が出力されますloadSettings() メソッドは、オブジェクトが作成されたときではなく、settings が最初にアクセスされたときにのみ実行されます。ただし、初期化される前に late 変数にアクセスすると、実行時エラーが発生するので注意してください。
チャレンジ
簡単late 変数を使用して、遅延初期化(deferred initialization)と遅延評価(lazy initialization)の両方を実演するデータベース接続マネージャーを作成しましょう。
コードを整理するために、2つのファイルを作成します:
database.dart: データベース接続をシミュレートするDatabaseクラスを定義します。クラスには以下の要素を含めてください:- オブジェクト作成後に設定される
late String connectionString Checking connection...と出力し、'Connected'を返す遅延初期化子を持つlate String statusconnectionStringを設定し、Connection configured: [connectionString]と出力するconnect(String connStr)メソッドExecuting on [connectionString]: [sql]と出力するquery(String sql)メソッドStatus: [status]と出力するcheckStatus()メソッド(これにより、最初の呼び出し時に遅延評価がトリガーされます)
- オブジェクト作成後に設定される
main.dart: データベースクラスをインポートし、lateの両方の使い方を実演します:Databaseインスタンスを作成するDatabase object createdと出力する- 接続文字列
'localhost:5432/mydb'を指定してconnect()を呼び出す 'SELECT * FROM users'を指定してquery()を呼び出すcheckStatus()を呼び出して遅延評価をトリガーする
connectionString がオブジェクト作成後に手動で設定される一方で、status は最初にアクセスされたときにのみ値を計算することに注目してください。
期待される出力:
Database object created
Connection configured: localhost:5432/mydb
Executing on localhost:5432/mydb: SELECT * FROM users
Checking connection...
Status: Connectedチートシート
late キーワードを使用すると、使用される前に後で初期化される非 null 許容変数を宣言できます。
class User {
late String username;
void initialize(String name) {
username = name;
}
}
User user = User();
user.initialize('Alice');遅延初期化: 初期化子を持つ late 変数は、最初にアクセスされたときにのみその値を計算します。
class Config {
late String settings = loadSettings();
String loadSettings() {
print('Loading...');
return 'default';
}
}
Config config = Config(); // loadSettings() はまだ呼び出されていません
print(config.settings); // ここで loadSettings() が呼び出されます警告: 初期化前に late 変数にアクセスすると、実行時エラーが発生します。
自分で試してみよう
import 'database.dart';
void main() {
// TODO: Database インスタンスを作成する
// TODO: 'Database object created' と出力する
// TODO: 'localhost:5432/mydb' を引数に指定して connect() を呼び出す
// TODO: 'SELECT * FROM users' を引数に指定して query() を呼び出す
// TODO: checkStatus() を呼び出して遅延初期化をトリガーする
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ