2021/4/16 :Flutter : freezedパッケージreadmeの訳パート2

 

<<前のページ


Unions/Sealed classes #

Coming from other languages, you may be used with features like “tagged union types” / sealed classes/pattern matching.

他の言語から来ている方は、”tagged union types”/sealed classes/pattern matchingなどを使ったことがあるかもしれません。

 

These are powerful tools in combination with a type system, but Dart currently does not support them.

これらは型システムと組み合わせた強力なツールですが、Dartは現在それらをサポートしていません。

 

Defining a union/sealed class with Freezed is simple: write multiple constructors:

Freezedではユニオン/シールクラスを定義するのは簡単です。複数のコンストラクターを記述します。

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = ErrorDetails;
}

This snippet defines a class with three states.

Note how we gave meaningful names to the right hand of the factory constructors we defined. They will come in handy later.

定義したファクトリコンストラクターの右側に意味のある名前を付けた方法に注意してください。 後で重宝します。


Shared properties

When defining multiple constructors, you will lose the ability to read properties that are not common to all constructors:

複数のコンストラクターを定義すると、「すべてのコンストラクターに共通ではないプロパティ」を読み取ることができなくなります。

例えば以下のように記述した時、

@freezed
class Example with _$Example {
  const factory Example.person(String name, int age) = Person;
  const factory Example.city(String name, int population) = City;
}

Then you will be unable to read age and population directly:

そうすると、ageとpopulationを直接読み取ることができなくなります。

var example = Example.person('Remi', 24);
print(example.age); // does not compile!

On the other hand, you can read properties that are defined on all constructors.
For example, the name variable is common to both Example.person and Example.city constructors.

As such we can write:

一方、すべてのコンストラクターで定義されているプロパティを読み取ることができます。
たとえば、name変数は、Example.personコンストラクターとExample.cityコンストラクターの両方に共通です。

そのため、次のように書くことができます。

var example = Example.person('Remi', 24);
print(example.name); // Remi
example = Example.city('London', 8900000);
print(example.name); // London

You also can use copyWith with properties defined on all constructors:

すべてのコンストラクターで定義されたプロパティでcopyWithを使用することもできます。

var example = Example.person('Remi', 24);
print(example.copyWith(name: 'Dash')); // Example.person(name: Dash, age: 24)

example = Example.city('London', 8900000);
print(example.copyWith(name: 'Paris')); // Example.city(name: Paris, population: 8900000)

To be able to read the other properties, you can use pattern matching thanks to the generated methods:

他のプロパティを読み取れるようにするために、生成されたメソッドのおかげでパターンマッチングを使用できます。

when
maybeWhen
map
maybeMap

Alternatively, you can use the is operator:

または、is演算子を使用することもできます。

var example = Example.person('Remi', 24);
if (example is Person) {
  print(example.age); // 24
}

 


When

The when method is the equivalent to pattern matching with destructing.
Its prototype depends on the constructors defined.

whenメソッドは、破壊を伴うパターンマッチングと同等です。
そのプロトタイプは、定義されたコンストラクターに依存します。

 

For example, with:

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = ErrorDetails;
}

Then when will be:

var union = Union(42);

print(
  union.when(
    (int value) => 'Data $data',//←多分$valueの間違いだと思われる。
    loading: () => 'loading',
    error: (String? message) => 'Error: $message',
  ),
); // Data 42

Whereas if we defined:

一方、下記のように定義した場合:

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

Then when will be:

var model = Model.first('42');

print(
  model.when(
    first: (String a) => 'first $a',
    second: (int b, bool c) => 'second $b $c'
  ),
); // first 42

Notice how each callback matches with a constructor’s name and prototype.

各コールバックでコンストラクターの名前とプロトタイプとどのように一致するかに注目してください。

NOTE:
All callbacks are required and must not be null.
If that is not what you want, consider using maybeWhen.

注意:
すべてのコールバックは必須であり、nullであってはなりません。
それが希望しない場合は、maybeWhenの使用を検討してください。


MaybeWhen #

The maybeWhen method is equivalent to when, but doesn’t require all callbacks to be specified.

On the other hand, it adds an extra orElse required parameter, for fallback behavior.

mayWhenメソッドはwhenと同等ですが、すべてのコールバックを指定する必要はありません。

一方、フォールバック動作のためにorElseパラメーターが必要です。

As such, using:

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String message]) = ErrorDetails;
}

Then we could write:

var union = Union(42);

print(
  union.maybeWhen(
    null, // ignore the default case
    loading: () => 'loading',
    // did not specify an `error` callback
    orElse: () => 'fallback',
  ),
); // fallback

This is equivalent to:

これは次と同等です。

var union = Union(42);

String label;
if (union is Loading) {
  label = 'loading';
} else {
  label = 'fallback';
}

But it is safer as you are forced to handle the fallback case, and it is easier to write.

ただし、フォールバックケースの処理を余儀なくされるため、より安全であり、記述も簡単です。


Map/MaybeMap #

The map and maybeMap methods are equivalent to when/maybeWhen, but without destructuring.

Consider this class:

mapメソッドとmaybeMapメソッドは、when / maybeWhenと同等ですが、破壊することはありません。

このクラスを検討してください。

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

With such class, while when will be:

var model = Model.first('42');

print(
  model.when(
    first: (String a) => 'first $a',
    second: (int b, bool c) => 'second $b $c'
  ),
); // first 42

map will instead be:

var model = Model.first('42');

print(
  model.map(
    first: (First value) => 'first ${value.a}',
    second: (Second value) => 'second ${value.b} ${value.c}'
  ),
); // first 42

This can be useful if you want to do complex operations, like copyWith/toString for example:

これは、たとえば次のようなcopyWith / toStringなどの複雑な操作を実行する場合に役立ちます。

var model = Model.second(42, false)
print(
  model.map(
    first: (value) => value,
    second: (value) => value.copyWith(c: true),
  )
); // Model.second(b: 42, c: true)

 

参考

https://pub.dev/packages/freezed#unionssealed-classes


FromJson/ToJson #

Freezedはそれ自体では典型的なfromJson / toJsonを生成しませんが、json_serializableが何であるかを知っています。

json_serializable と互換性のあるクラスを作るのはとても簡単です。

このスニペットを考えてみましょう。

import 'package:freezed_annotation/freezed_annotation.dart';

part 'model.freezed.dart';

@freezed
abstract class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

json_serializableと互換性を持たせるためには、以下のように変更します。

import 'package:freezed_annotation/freezed_annotation.dart';

part 'model.freezed.dart';
part 'model.g.dart';

@freezed
abstract class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;

  factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);
}

以上です。

これらの変更により、Freezedは自動的にjson_serializableに対して、必要なすべてのfromJson/toJsonを生成するように要求します。


fromJSON – classes with multiple constructors

For classes with multiple constructors, Freezed will check the JSON response for a string element called runtimeType and choose the constructor to use based on its value. For example, given the following constructors:

複数のコンストラクターを持つクラスの場合、FreezedはruntimeTypeという文字列要素のJSON応答をチェックし、その値に基づいて使用するコンストラクターを選択します。 たとえば、次のコンストラクターがあるとします。

@freezed
class MyResponse with _$MyResponse {
  const factory MyResponse(String a) = MyResponseData;
  const factory MyResponse.special(String a, int b) = MyResponseSpecial;
  const factory MyResponse.error(String message) = MyResponseError;

  factory MyResponse.fromJson(Map<String, dynamic> json) => _$MyResponseFromJson(json);
}

Then Freezed will use each JSON object’s runtimeType to choose the constructor as follows:

次に、Freezedは各JSONオブジェクトのruntimeTypeを使用して、次のようにコンストラクターを選択します。

[
  {
    "runtimeType": "default",
    "a": "This JSON object will use constructor MyResponse()"
  },
  {
    "runtimeType": "special",
    "a": "This JSON object will use constructor MyResponse.special()",
    "b": 42
  },
  {
    "runtimeType": "error",
    "message": "This JSON object will use constructor MyResponse.error()"
  }
]

 

工事中🏗

https://pub.dev/packages/freezed#the-syntax

コメントを残す

メールアドレスが公開されることはありません。