大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

Flutterにおけるfreezed使用

著者:津路高広
公開日:2023/04/27
最終更新日:2023/04/27
カテゴリー:技術情報
タグ:

津路です。こんにちは、今年の春は、気温の上下が大きい方だと感じています。

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');

すごい!

    上に戻る