如何用 dartz 重构 flutter 中的功能性错误处理
How to refactor functional error handling in flutter with dartz
我有两个方法
@override
Future<Option<StorageFailure>> init() async {
final root = await getRootDir();
return root.fold(
(failure) => some(failure),
(dir) {
final images = Directory("$dir/images");
final videos = Directory("$dir/videos");
images.create(); // more error handling here (try|either)
videos.create();
},
);
}
@override
Future<Either<StorageFailure, Directory>> getRootDir() async {
try {
final root = await getApplicationDocumentsDirectory();
return right(Directory("${root.path}/files"));
} catch (e) {
return left(StorageFailure(reason: e.toString()));
}
}
在折叠后的 init
方法上,我需要做更多的错误处理,但我不喜欢嵌套太多我的代码。我也不知道如何从 right
函数 return a Failure
。
链接这些值的更好方法是什么?
Either 的妙处在于,您可以链接操作并在最后处理一次错误。如果程序无法获取根目录,则永远不会执行创建媒体子目录的部分。所以不需要嵌套的错误处理。
我自己正在学习函数式编程。所以可能有更好的解决方案,但我会这样做:
// I intentionally added all type annotations for better understanding.
Future<Option<StorageFailure>> init() async {
final Either<StorageFailure, Directory> root = await getRootDir();
final Either<StorageFailure, Either<StorageFailure, Success>> result = await root.traverseFuture(createImagesAndVideosSubfolders);
final Either<StorageFailure, Success> flattenedResult = result.flatMap(id);
return flattenedResult.fold((failure) => some(failure), (success) => none());
}
Future<Either<StorageFailure, Success>> createImagesAndVideosSubfolders(Directory dir) async {
try {
await Directory('${dir.path}/images').create();
await Directory('${dir.path}/videos').create();
return right(Success('success'));
} catch (e) {
return left(StorageFailure(reason: e.toString()));
}
}
- 获取根目录
- 创建媒体目录(如果 getRootDir 失败,root.traverseFuture 方法只是 returns 现有的 StorageFailure)
- 使用 flatMap 和 id 函数将嵌套的 Eithers 展平。 traverseFuture 方法是期货的地图版本。如果 futures 也有一个 flatMap 等价物,结果就不会被包裹在 either 中,最后一步就不需要展平结果了。
您可以通过返回 Either 而不是将其转换为 Option 来进一步简化 init 函数。
像这样:
Future<Either<StorageFailure, Success>> init() async {
...
return result.flatMap(id);
}
我有两个方法
@override
Future<Option<StorageFailure>> init() async {
final root = await getRootDir();
return root.fold(
(failure) => some(failure),
(dir) {
final images = Directory("$dir/images");
final videos = Directory("$dir/videos");
images.create(); // more error handling here (try|either)
videos.create();
},
);
}
@override
Future<Either<StorageFailure, Directory>> getRootDir() async {
try {
final root = await getApplicationDocumentsDirectory();
return right(Directory("${root.path}/files"));
} catch (e) {
return left(StorageFailure(reason: e.toString()));
}
}
在折叠后的 init
方法上,我需要做更多的错误处理,但我不喜欢嵌套太多我的代码。我也不知道如何从 right
函数 return a Failure
。
链接这些值的更好方法是什么?
Either 的妙处在于,您可以链接操作并在最后处理一次错误。如果程序无法获取根目录,则永远不会执行创建媒体子目录的部分。所以不需要嵌套的错误处理。
我自己正在学习函数式编程。所以可能有更好的解决方案,但我会这样做:
// I intentionally added all type annotations for better understanding.
Future<Option<StorageFailure>> init() async {
final Either<StorageFailure, Directory> root = await getRootDir();
final Either<StorageFailure, Either<StorageFailure, Success>> result = await root.traverseFuture(createImagesAndVideosSubfolders);
final Either<StorageFailure, Success> flattenedResult = result.flatMap(id);
return flattenedResult.fold((failure) => some(failure), (success) => none());
}
Future<Either<StorageFailure, Success>> createImagesAndVideosSubfolders(Directory dir) async {
try {
await Directory('${dir.path}/images').create();
await Directory('${dir.path}/videos').create();
return right(Success('success'));
} catch (e) {
return left(StorageFailure(reason: e.toString()));
}
}
- 获取根目录
- 创建媒体目录(如果 getRootDir 失败,root.traverseFuture 方法只是 returns 现有的 StorageFailure)
- 使用 flatMap 和 id 函数将嵌套的 Eithers 展平。 traverseFuture 方法是期货的地图版本。如果 futures 也有一个 flatMap 等价物,结果就不会被包裹在 either 中,最后一步就不需要展平结果了。
您可以通过返回 Either 而不是将其转换为 Option 来进一步简化 init 函数。
像这样:
Future<Either<StorageFailure, Success>> init() async {
...
return result.flatMap(id);
}