Flutterにおけるfreezed使用

津路です。こんにちは、今年の春は、気温の上下が大きい方だと感じています。
freezedパッケージは、Dartパッケージなのですが、なぜ必要かというと、
Dart is awesome, but defining a “model” can be tedious
とあります通り、本体ではモデルを定義するには物足りない。
コンストラクタとプロパティ、toString, == operator, hashCode, copyWith, シリアライゼーションなんぞをゴリゴリしなければならない。
パターンマッチング、ユニオン機能がない。
ということで、このパッケージを、build_runnerとともに使うと、生成してくれるという、珍しい存在です。
freezed_annotationというパッケージはこれに付属して、@freezedのついたクラスのコードの生成に役立ちます。ただし、これはユーザが作るプロジェクトのpubspec.yaml内で、dependencies項目に入れる必要があります。
クラス名の前に_$をつけた名前を記述する必要があります。
コンストラクタにはfactoryをつける必要があります。
こうすることで、immutableになるわけですが、Flutterではこれが重要で、クラスインスタンスの使い回しができないようにしているわけですね。
が、オプションもありまして、
@unfreezedを使うと、一部のプロパティにfinalを省いて、そのプロパティだけ、可変にできるわけなんですねえ。
その代わり、インスタンスの比較式 == では、同じプロパティ値でも等式が成り立たないことになります。
さて、このパッケージの説明で、以下のコードがあります。
@freezed class Example with _$Example { factory Example(List<int> list) = _Example; } void main() { var example = Example([]); example.list.add(42); // throws because we are mutating a collection }
この例外に対応するには、
makeCollectionsUnmodifiable: false
をつけると、mutableにできちゃう、ということで、便利です。
また、別の便利な機能として、クラス同士関連のある場合に、copyWithが簡単なコードで済ませられる。
@freezed class Company with _$Company { factory Company({String? name, required Director director}) = _Company; } @freezed class Director with _$Director { factory Director({String? name, Assistant? assistant}) = _Director; } @freezed class Assistant with _$Assistant { factory Assistant({String? name, int? age}) = _Assistant; }
と、Company>Director>Assistantという親子関係の状態で、Assistantの名前を指定してクローンする場合、
Company company; Company newCompany = company.copyWith( director: company.director.copyWith( assistant: company.director.assistant.copyWith( name: 'John Smith', ), ), );
という複雑なコーディングが、以下の1行で済むというんですね。
Company company; Company newCompany = company.copyWith.director.assistant(name: 'John Smith');
すごい!