はじめに
enumの列挙子の引数ごとに異なる型のデータを渡しつつ、呼び出し側で型安全に扱いたい場面がありました。
この記事では、enum側をジェネリクス化することで呼び出し側では型安全に扱えるようにした際の対応方法をまとめています。
まずは様々な型のデータを扱えるようにする
開発しているときに、アプリ内の設定項目をenumとして定義し、各設定にデフォルト値を持たせたい場面がありました。
今回はその場面を想定して話を進めます。
まず、素直に書くと以下のようになります。
enum AppSettings {
volume(0.5), // 音量 double
darkMode(false), // ダークモード bool
theme(0); // テーマ int
final dynamic defaultValue;
const AppSettings(this.defaultValue);
}
これでとりあえず様々な型のデータをdefaultValueに入れられます。
しかし、このコードだとdefaultValueがdynamicになるため、呼び出し側で型チェックやキャストが必要になり、扱いづらくなります。
final v = AppSettings.theme.defaultValue;
final theme = (v is int) ? v : 0;
次は、呼び出し側で型安全に扱えるようにしていきます。
型安全に扱えるように改良
enumをジェネリクス化します。
列挙子ごとに型引数(<int>とか<double>のやつ)を指定し、引数に異なる型のデータを渡しています。
enum AppSettings<T> {
volume<double>(0.5),
darkMode<bool>(false),
theme<int>(0);
final T defaultValue;
const AppSettings(this.defaultValue);
}
これで呼び出し側は、型チェックなしで型安全に扱えるようになります。
final volume = AppSettings.volume.defaultValue; // double
final darkMode = AppSettings.darkMode.defaultValue; // bool
final theme = AppSettings.theme.defaultValue; // int
注意点
AppSettings.values自体は取得できますが、設定ごとに型が異なるため、valuesをループで回すと要素の型がdynamicになります。
そのため、valuesを使って一括処理したい場合は、用途に応じて工夫が必要になります。
今回のケースではvaluesを使う予定がなかったため、ここは深掘りしませんでしたが、運用途中で必要になる可能性がある点として覚えておくと良いと思います。