Open3
Dart 3のsealed classメモ
Dart 3のsealed classを試してみたのでメモ。
dart 2 + freezedで書いていたunion。
class LoadParams<PageKey> with _$LoadParams<PageKey> {
const factory LoadParams.refresh() = _LoadParamsRefresh;
const factory LoadParams.prepend({
required PageKey key,
}) = _LoadParamsPrepend;
const factory LoadParams.append({
required PageKey key,
}) = _LoadParamsAppend;
}
dart 3ではsealed classが利用できる。
sealed class LoadAction<PageKey> {
const LoadAction._();
}
class Refresh<PageKey> implements LoadAction<PageKey> {
const Refresh();
}
class Prepend<PageKey> implements LoadAction<PageKey> {
const Prepend({
required this.key,
});
final PageKey key;
}
class Append<PageKey> implements LoadAction<PageKey> {
const Append({
required this.key,
});
final PageKey key;
}
unionを利用するには、switch
が使える。
dart 2 + freezedの場合のコード。
Future<LoadResult<int, Repository>> load(LoadParams<int> params) async {
return params.when(
refresh: () async {
final data = await repository.repositories();
return LoadResult.success(
page: data,
);
},
prepend: (_) {
return const LoadResult.none();
},
append: (key) async {
final data = await repository.repositories(
since: key,
);
return LoadResult.success(
page: data,
);
},
);
}
dart 3のsealed classでは、次の2つの書き方ができる様子。
なおLoadResult
も同様に置き換えている。
Future<LoadResult<int, Repository>> load(LoadAction<int> params) async {
switch (params) {
case Refresh():
await fetch(null);
break;
case Prepend(key: final _):
const None();
break;
case Append(key: final key):
await fetch(key);
break;
}
}
=>
で繋ぐと、 {}
が利用できない。
Future<LoadResult<int, Repository>> load(LoadAction<int> params) async =>
switch (params) {
Refresh() => await fetch(null),
Prepend(key: final _) => const None(),
Append(key: final key) => await fetch(key),
};
Future<LoadResult<int, Repository>> fetch(int? key) async {
final PageData<int, Repository> data;
if (key == null) {
data = await repository.repositories();
} else {
data = await repository.repositories(
since: key,
);
}
return Success(
page: data,
);
}
switch
を条件分岐で使う(case
)場合と、式として使う(final result = switch
)場合で記述方法が変わるらしい。
switch (result) {
case Success(page: final page):
_manager.append(page);
break;
case Failure(e: final e):
_manager.setError(e);
break;
case None():
_manager.append(null);
break;
}
final _ = switch (result) {
Success(page: final page) => _manager.append(page),
Failure(e: final e) => _manager.setError(e),
None() => _manager.append(null),
};
ただしvoid
をfinal _
で受け取ろうとすると、次のコンパイルエラーがでる。
Error: This expression has type 'void' and can't be used.
Dart 3でbreak
が必須でなくなったので、次のように書いた方がシンプル。
switch (result) {
case Success(page: final page):
_manager.append(page);
case Failure(e: final e):
_manager.setError(e);
case None():
_manager.append(null);
}