Dartの世界へようこそ。言語の深淵を覗く準備はいいですか?
多くの開発者が`var`, `final`, `const`を単なる「書き方の違い」として捉えていますが、それは非常にもったいないことです。これらは単なる文法ではなく、あなたの書いたコードがメモリ上でどう生きていくか、そしてDart VMがどうそれを最適化するかを制御する「司令塔」なのです。
今日は、その本質をDartコアの視点から紐解いていきましょう。
—
1. 変数の「実体」と「参照」を理解する
まず、Dartのメモリモデルを知る必要があります。Dartにおいて変数は「データそのもの」を入れる箱ではなく、「データが置かれている場所(メモリ上のアドレス)」を指し示すポインタのようなものです。
var:再代入可能な「しなやかな器」
`var`は、Dartに型推論を任せる柔軟な宣言です。
var name = “Dart”; // 型はStringと推論される
name = “Flutter”; // OK: 別の文字列(の参照先)に差し替え可能
`var`は、実行時に値が変化することを許容します。その分、Dart VMは「この変数は後で変わるかもしれない」という前提でメモリを確保するため、コンパイル時の最適化の余地は限定的になります。
—
2. final:実行時の「不変(Immutable)の守り神」
`final`は、「一度決めたら二度と変えない」という強い意志を示すキーワードです。
final timestamp = DateTime.now(); // 実行時の値で初期化
// timestamp = DateTime.now(); // エラー: 再代入は許されない
ここが重要なポイントです。`final`の値が決まるのは「実行時(Runtime)」です。`DateTime.now()`のように、プログラムを走らせて初めてわかる値であっても、`final`なら安全に扱うことができます。
- Dart VMの視点: 「この変数は絶対に書き換わらない」とわかっているため、VMはこのメモリ領域を安全な場所としてキャッシュしやすく、パフォーマンス向上に寄与します。
—
3. const:コンパイル時の「永遠の結晶」
`const`は、Dartにおいて最も強力なキーワードです。これは単なる「変更不可」ではありません。「プログラムが始まる前(コンパイル時)に、その値が完全に確定している」ことを意味します。
const pi = 3.14;
// const now = DateTime.now(); // エラー: 実行時の値はconstにはできない
なぜconstが最強なのか?「定数プール」の秘密
`const`が宣言されると、Dartコンパイラはそれを「定数プール(Constant Pool)」という特別なメモリ領域に配置します。
もしコード内で同じ`const`値を100回使ったとしても、メモリ上には「たった1つの値」しか存在しません。100個の変数すべてが、定数プールにある同じアドレスを指すからです。これはメモリ消費を劇的に抑え、ガベージコレクション(GC)の負荷を軽減します。
—
4. 迷わないための使い分けチャート
現場で迷ったときは、この優先順位で考えてみてください。
1. まずは `const` を検討する:
- コンパイル時に値が決まるか?(リテラル、数値、定数同士の計算など)
- はい → 迷わず `const`。これが最もメモリに優しく、爆速です。
2. 次に `final` を検討する:
- 実行時に一度だけ値が決まり、その後は変わらないか?(APIのレスポンス、コンストラクタの引数など)
- はい → `final`。副作用を防ぐ基本です。
3. 最後に `var` を検討する:
- ループ変数や、明確に状態を変化させる必要がある場合のみ。
- `var`を使うときは「この変数は変わるんだ」という意図を明確にしましょう。
—
5. 陥りやすい罠:オブジェクトの「参照」と「中身」
ここで一つ、中級者でも躓くポイントを。
final list = [1, 2, 3];
list.add(4); // これはエラーにならない!
なぜか? `final`が守っているのは「変数`list`が指し示すメモリアドレス」だからです。リストの中身(オブジェクトの状態)までを凍結しているわけではありません。
もし完全に「中身すら変えさせない」のであれば、`const`を使う必要があります。
const list = [1, 2, 3];
// list.add(4); // コンパイルエラー!
`const`を付けると、そのリストは「コンパイル時に凍結されたデータ」となり、一切の変更が許されなくなります。
—
まとめ:Dartを掌握するということ
- `var`: 変化を許容する柔軟な器。
- `final`: 実行時に一度だけ値を確定させ、以降は変更させない「安全装置」。
- `const`: コンパイル時に全てを解決し、メモリを極限まで最適化する「定数」。
これらを正しく使い分けるだけで、あなたの書くDartコードは「ただ動くコード」から「Dart VMに愛される効率的なコード」へと進化します。
「何となく`var`でいいや」を卒業し、変数の重みを感じながらコードを書く。その一歩が、あなたを真のDartエンジニアへと引き上げます。今日からぜひ、コードの先にあるメモリの動きを想像してみてくださいね!