はじめに
Dart 2.17 以降、enum が大幅に進化しました。
単なる「定数の集まり」ではなく、クラスのようにプロパティやメソッドを持つことができるようになっています。
この記事では、旧来の enum との違いと、新しい「拡張列挙」の活用法を整理します✨
1. そもそも enum とは?
旧バージョン(Dart 2.16 以前)
Dart の enum は、単に「名前付き定数」を定義する仕組みでした。
enum Color {
red,
green,
blue,
}
void main() {
print(Color.red); // Color.red
print(Color.values); // [Color.red, Color.green, Color.blue]
}
特徴
-
Color.redのように呼び出す -
valuesで全列挙を取得できる - ただし、フィールドやメソッドは持てない
2. Dart 2.17 〜「拡張列挙(Enhanced Enums)」登場!
Dart 2.17 からは、enum が クラスのように扱えるようになりました。
つまり、プロパティ・メソッド・コンストラクタ・インターフェース実装が可能です!
例:プロパティ付きの拡張列挙
enum Color {
red(0xFF0000),
green(0x00FF00),
blue(0x0000FF);
// プロパティ
final int hex;
// コンストラクタ
const Color(this.hex);
// メソッド
void describe() {
print('Color: $name (#${hex.toRadixString(16)})');
}
}
void main() {
Color.red.describe(); // Color: red (#ff0000)
print(Color.green.hex); // 65280
}
ポイント
-
;(セミコロン)が列挙値の後に必要 -
finalフィールドを定義できる - コンストラクタを
constで指定可能 - メソッドを定義できる
-
nameやindexプロパティも利用可能
3. 実装型(インターフェース)も指定できる
拡張列挙は、implements を使ってインターフェースを実装することもできます。
abstract class Describable {
String describe();
}
enum VehicleType implements Describable {
car('Four wheels'),
bike('Two wheels');
final String info;
const VehicleType(this.info);
@override
String describe() => 'Vehicle: $name, info: $info';
}
void main() {
print(VehicleType.car.describe());
// => Vehicle: car, info: Four wheels
}
→ クラスのように「契約を守る列挙型」が作れる!
4. メソッドやゲッターも活用できる
例:条件分岐を内包する enum
enum Planet {
mercury(3.303e+23, 2.4397e6),
earth(5.976e+24, 6.37814e6),
mars(6.421e+23, 3.3972e6);
final double mass; // kg
final double radius; // meters
const Planet(this.mass, this.radius);
double get surfaceGravity => 6.67300e-11 * mass / (radius * radius);
double weight(double mass) => mass * surfaceGravity;
}
void main() {
final earthWeight = 70;
for (final planet in Planet.values) {
final weight = planet.weight(earthWeight);
print('${planet.name}: ${weight.toStringAsFixed(2)} N');
}
}
→ 列挙型の中で、各要素ごとに物理計算を行うことが可能です。
Javaの「Enumクラス」に近い強力な表現ができるようになりました。
5. クラスとの比較
| 機能 | 通常の enum | 拡張列挙 (2.17〜) | クラス |
|---|---|---|---|
| 定数の定義 | ✅ | ✅ | ❌ |
| フィールド保持 | ❌ | ✅ | ✅ |
| メソッド定義 | ❌ | ✅ | ✅ |
| コンストラクタ | ❌ | ✅ | ✅ |
| インターフェース実装 | ❌ | ✅ | ✅ |
| 継承 | ❌ | ❌ | ✅(1つだけ) |
→ 「拡張列挙」は、クラスと enum の中間に位置する機能です。
6. Flutterでの実践例
Flutterでも、この機能はよく使われています。
たとえば「テーマモード」や「ステータス」を表すときなど。
enum ThemeMode {
light('明るいテーマ', 0xFFFFFF),
dark('暗いテーマ', 0x000000);
final String label;
final int color;
const ThemeMode(this.label, this.color);
bool get isDark => this == ThemeMode.dark;
}
@override
Widget build(BuildContext context) {
final theme = ThemeMode.dark;
return Container(
color: Color(theme.color),
child: Text(theme.label),
);
}
→ 文字列ラベルや色コードを直接保持できるので、
以前より enum の使い勝手が格段に上がっています。
7. switch と組み合わせて型安全に!
Dartの switch 文は、enumと非常に相性が良いです。
全ケースを網羅しないとコンパイルエラーを出せるため、安全な分岐処理が可能です。
enum Status { idle, loading, success, error }
String getMessage(Status status) {
return switch (status) {
Status.idle => '待機中',
Status.loading => '読み込み中...',
Status.success => '成功!',
Status.error => 'エラー発生!',
};
}
Dart 3.0 の
switch式(pattern matching)との連携も◎
enumを exhaustiveness(網羅性)チェック付きで安全に使えます。
まとめ
| 機能 | 説明 |
|---|---|
enum |
定数の集まり(Dart 2.16以前) |
| 拡張列挙 | プロパティ・メソッド・コンストラクタを持つ強化版 |
implements |
インターフェース実装も可能 |
switch |
型安全な網羅チェック付きで分岐可能 |