こんにちは!Dartの奥深い世界へようこそ。世界最高峰のDartコアコミッターである私が、今日あなたを「宣言的UIやデータ構築のマスター」へと導きます。
FlutterやDartを使っていると、画面のレイアウトだけでなく、データそのものを組み立てる時にも「あれ、ここでif文やfor文を使いたいけれど、どう書けばスマートだろう?」と悩むことってありませんか?他の言語から来た方だと、わざわざ空のリストを作ってから`if`で要素を`add`したり、面倒な手続き型コードを書きがちですよね。
でも、Dartにはコレクションリテラル内での`if`と`for`(Collection If / Collection For)という、美しく洗練された奥義が備わっています。ここをクリアすれば、あなたのDartコードは一気にモダンで、読みやすく、そして強固なものになりますよ。
さあ、一緒にその本質を見ていきましょう!
—
1. 従来の「泥臭い」コードからの脱却
まずは、他の言語や昔ながらの手法でよく見かける、こんなコードを思い浮かべてみてください。
// 従来の命令型アプローチ
List
List
if (isLoggedIn) {
items.add(‘マイページ’);
items.add(‘ログアウト’);
} else {
items.add(‘ログイン’);
}
return items;
}
このコード、動くには動きますが、「可変(Mutable)なリストを宣言して、後からグニャグニャと要素を付け足す」という構造になっています。これではコードが長くなり、意図が少し見えにくくなってしまいますよね。
Dartの設計思想の根底には「不変性(Immutability)と宣言的構築の愛の深さ」があります。コンパイラやVMにとっても、最初から最終的なリストの形がパッと決まっている方が、最適化の面でも非常に嬉しいのです。
そこで登場するのが、コレクションリテラル内での`if`と`for`です。
—
2. Collection If:条件に応じたスマートな要素の挿入
まずは `if` からいきましょう。リストやマップの中に、直接条件分岐を組み込むことができます。
List
return [
‘ホーム’,
‘設定’,
if (isLoggedIn) …[
‘マイページ’,
‘ログアウト’,
] else …[
‘ログイン’,
],
];
}
おっと、見慣れない記号 `…` が出てきましたね!これはスプレッド演算子(Spread Operator)と呼ばれ、「あるリストの中身を、そのまま別のリストにブチ込む(展開する)」という魔法の構文です。
ここがポイント!
- `if (isLoggedIn)` の後ろには、単一の要素(例: `’マイページ’`)をそのまま置くこともできます。
- 複数の要素をまとめて出し入れしたいときは、スプレッド演算子 `…[…]` を使ってリストを展開します。
- これにより、リストを `final` (または `const`)として宣言したまま、安全に組み立てることが可能になります。
—
3. Collection For:ループによるデータの爆速生成
次に、コレクション内でループを回す `for` の使い方を見てみましょう。例えば、「1から3までの数字をプレフィックス付きでリスト化したい」という場合、こう書けます。
void main() {
int maxCount = 3;
List さて、ここで初心者がハマりがちな「罠」をいくつかご紹介しておきましょう。これをあらかじめ知っておくだけで、無駄なコンパイルエラーに悩まされずに済みますよ。 通常のDartの文(Statement)では末尾にセミコロンを書くため、うっかりコレクション内でも書いてしまいがちです。 List 【解決策】 もしリストを `const`(コンパイル時定数)にしたい場合、実行時に決まる変数や条件分岐は使えません。 const bool isDebug = bool.fromEnvironment(‘DEBUG’); const List Dart VMは、`const` で宣言されたコレクションをコンパイル時に完全に評価し、メモリ上のイミュータブルな領域に焼き付けます。そのため、実行時に関数が評価されるような処理を `const` 内の `if` や `for` に混ぜると、怒られてしまいます。 — 最後に、少しだけアーキテクトらしい話をさせてください。 なぜ、ここまで「宣言的なコレクション構築」を私たちが推すのか? 命令型で `add` を繰り返すコードは、背後で何度もリストのメモリ領域の再割り当て(リサイズ)が発生するリスクを孕んでいます。しかし、コレクションリテラル内で `if` や `for` を使った宣言的コードであれば、コンパイラは「このデータ構造の最終形態はこれだ」と一目で理解し、無駄なオーバーヘッドのない美しいバイトコードを生成できます。 パフォーマンスが高く、バグが入り込む隙がなく、何より人間にとっても読みやすい。――これを使わない手はありませんよね。 — ここをクリアすれば、あなたのDartの基礎力は確実に次のステージへとステップアップしています。ぜひ今日からのコードで、スマートなコレクション構築をバンバン試してみてくださいね!それではまた、次回の極限の知見でお会いしましょう。
‘一般’,
for (int i = 1; i <= maxCount; i++) 'タグ_$i',
];
print(tags);
// 実行結果: [一般, タグ_1, タグ_2, タグ_3]
}
どうですか?わざわざ外部でループを回して `add` する必要がなく、リストの波括弧 `[]` の中で完結していますよね。データ構造の見た目と、実際のデータの配置が1対1で脳内リンクするため、コードの可読性が劇的に向上します。
もちろん、Map(マップ)の構築時にも `for` や `if` は大活躍します。
void main() {
final keys = ['id', 'name', 'role'];
final values = [101, 'Alice', 'Admin'];
// 2つのリストからMapを宣言的に構築する
final Map
for (int i = 0; i < keys.length; i++) keys[i]: values[i],
'isActive': true, // 条件付きで追加することも可能
};
print(userMap);
// 実行結果: {id: 101, name: Alice, role: Admin, isActive: true}
}
---
4. 陥りやすい文法エラーと、その回避の極意
罠その1:セミコロン(`;`)を書いてしまう
1,
2,
if (true) 3;, // ❌ エラー!コンパイルエラーになります
];
コレクションリテラルの中は、あくまで「式(Expression)」の世界です。`if` や `for` の中身であっても、文の終わりのセミコロンは不要です。要素と要素の区切りは、あくまでのカンマ(`,`)です。罠その2:constコンテキストでの動的条件
‘api_endpoint’,
if (isDebug) ‘debug_tools’, // ⭕️ これはOK!isDebugがconstのため
// if (DateTime.now().hour > 12) ‘afternoon’, ❌ 実行時関数はconst内ではNG
];5. Dart VMの裏側と、私たちがこの書き方を選ぶ理由
それは、Dartのコンパイラ(AOTコンパイラ)とJIT(Just-In-Time)VMが、「最初からサイズと構造が確定しているイミュータブルなデータ構造」に対して、最も効率的なメモリ割り当てと最適化を行えるからです。まとめ