DartのNull安全を極める:List
DartのSound Null Safetyは、単なる「エラーを防ぐためのガードレール」ではない。それは、コンパイラが型情報というメタデータをもとに、実行時コストを最小化するための強力な武器だ。
特に、外部APIや非同期ストリームから流れてくる `List
本稿では、Dart VMの挙動を理解した上で、最も洗練された「型抽出」の作法を伝授する。
—
1. なぜ「手動フィルタリング」は非効率なのか
多くのエンジニアがやってしまいがちなのが、`where` を使ったフィルタリングだ。
// アンチパターン:読みやすいが、実行効率と型推論の観点で損をしている
final rawList =
final cleanList = rawList.where((e) => e != null).map((e) => e!).toList();
このコードの何が問題か?
1. 二重のイテレーション: `where` で一度走査し、`map` で再度走査する。リストが巨大な場合、メモリキャッシュの効率を落とす。
2. 手動キャストの強制: `e!` と書くことで、コンパイラに対して「ここは絶対にnullじゃない」と無理やり教え込んでいる。これはSound Null Safetyの理念に反する。
—
2. 究極の解答:`whereType()` の真価
Dartの標準ライブラリには、この問題をエレガントかつ高速に解決するためのメソッド、`whereType
final rawList =
// 模範解答:型抽出とフィルタリングを同時に行う
final cleanList = rawList.whereType
なぜこれが「最強」なのか
- 単一パスの走査: Dart VMレベルで最適化されたイテレータが、内部で型チェックと抽出を同時に行う。
- Soundnessの保証: `whereType
()` を呼び出した時点で、結果は確実に `Iterable ` となる。`!` を使う必要は皆無だ。 - 遅延評価: `toList()` を呼ぶ直前まで、この操作は「ビュー」として保持される。メモリの無駄な確保を最小限に抑えることができる。
—
3. 実践:非同期API連携における堅牢なパターン
Webエンジニアが最も遭遇する「JSONパース後のリスト処理」を例に、実務で即戦力となる堅牢な設計を示そう。
// APIから返ってきた不完全なデータ構造を想定
final responseData =
/// 安全に特定の型のみを抽出する拡張メソッド
extension SafeListExtraction on Iterable {
List
}
void main() {
// 型安全かつ保守性の高いパイプライン
final validIds = responseData
.filterType
print(validIds.toList()); // [1, 2]
}
この設計の肝は、「段階的に型を絞り込むこと」にある。最初から完璧なパースを求めず、パイプラインの各ステージで `whereType` を活用することで、バリデーションと変換を分離し、可読性と安全性を両立させている。
—
4. チーフアーキテクトからの助言
Dart VMは、`whereType
結論:
- `!`(Bang演算子)を多用しているコードは、型設計の敗北である。
- リストの変換には常に `whereType
()` を優先せよ。 - 複雑なデータ操作は、拡張メソッドとして切り出し、再利用可能なユーティリティにせよ。
コードは、書いた本人以外の誰かが修正する。そのとき「なぜこの書き方なのか」という意図が、Dartの言語仕様に基づいたロジックで裏付けられているか。それこそが、シニアエンジニアとそうでない者を分かつ境界線だ。
さあ、あなたのコードから不要な `!` を排除し、型安全という名の平穏を手に入れよう。