Flutter类型化结果处理插件typed_result的使用

发布于 1周前 作者 nodeper 来自 Flutter

Flutter类型化结果处理插件typed_result的使用

typed_result 插件提供了一个方便的 Result 单子(monad),用于表示成功和错误。Result<T, E> 类可以是成功 (Ok<T>) 或者错误 (Err<E>)。

特性

typed_result 插件提供了以下便利方法:

  • 获取值getgetOrgetOrThrowgetErrorgetErrorOrgetErrorOrThrow
  • 映射 ResultmapmapErrormapBoth
  • 基于结果执行代码块onSuccessonFailurewhen
  • 捕获异常并转换为错误runCatching
  • 根据空值将任何对象包装为 ResulttoResultOr
  • 测试 Result 的自定义匹配器

使用方法

Result<T, E> 不能直接实例化。要创建一个 Result,只需创建 Ok<T>Err<E> 的实例。

var result = Ok(1); // 作为 Ok<int>
var result = Err(""); // 作为 Err<String>
Result<int, String> result = Ok(1); // 作为 Result<int, *>, 其中 * 可以是任何类型
Result<int, String> result = Err(""); // 作为 Result<*, String>, 其中 * 可以是任何类型

// 作为函数的返回值
Result<int, String> getData() {
  if (condition) {
    return Ok(1);
  } else {
    return Err("");
  }
}

完整示例Demo

以下是一个完整的示例,展示了如何使用 typed_result 插件的各种功能:

// ignore_for_file: avoid_print

import 'package:typed_result/typed_result.dart';

class DateException implements Exception {}

class ChildDateException implements DateException {}

/// 模拟一个真实的仓库调用,通常会有一个自定义类来表示预期的失败。
/// 如果 [forceFailure] 为 false,则正常返回当前日期的 `Ok`。
/// 如果 [forceFailure] 为 true,则返回自定义异常类的 `Err`。
Result<DateTime, DateException> getDate(bool forceFailure) {
  var now = DateTime.now();
  if (!forceFailure) {
    return Ok(now);
  } else {
    return Err(DateException());
  }
}

void main() async {
  var ok = getDate(false);
  var err = getDate(true);

  /// 展示 `Result` 实例的属性
  void instances() {
    print("\nInspecting instances of Result");
    print(ok);
    print("ok.isSuccess: ${ok.isSuccess}");
    print("ok.isFailure: ${ok.isFailure}");

    print(err);
    print("err.isSuccess: ${err.isSuccess}");
    print("err.isFailure: ${err.isFailure}");
  }

  /// 展示如何从 `Result` 中获取值
  void getters() {
    print("\n`get`");
    print(ok.get()); // 获取成功值
    try {
      print(err.get()); // 尝试获取失败值,会抛出异常
    } catch (e) {
      print("Exception was thrown because it was a failure result");
    }

    print("\n`getOr`");
    print(ok.getOr(() => DateTime(2000))); // 获取成功值或默认值
    print(err.getOr(() => DateTime(2000))); // 获取失败值或默认值

    print("\n`getOrThrow`");
    print(ok.getOrThrow()); // 获取成功值或抛出异常
    try {
      err.getOrThrow(); // 尝试获取失败值,会抛出异常
    } catch (e) {
      print("Exception was thrown because it was a failure result");
    }

    print("\n`getError`");
    print(ok.getError()); // 获取成功结果的错误值,返回 null
    print(err.getError()); // 获取失败结果的错误值

    print("\n`getErrorOr`");
    print(ok.getErrorOr(() => ChildDateException())); // 获取成功结果的错误值或默认值
    print(err.getErrorOr(() => ChildDateException())); // 获取失败结果的错误值或默认值

    print("\n`getErrorOrThrow`");
    try {
      ok.getErrorOrThrow(); // 获取成功结果的错误值或抛出异常
    } catch (e) {
      print("Exception was thrown because it was a success result");
    }
    print(err.getErrorOrThrow()); // 获取失败结果的错误值
  }

  /// 展示如何将当前 `Result` 值映射为新的 `Result`
  void map() {
    print("\n`map`");
    print(ok.map((value) => "Mapping success at $value")); // 映射成功值
    print(err.map(noop)); // 映射失败值,不会执行

    print("\n`mapError`");
    print(ok.mapError(noop)); // 映射成功值的错误,不会执行
    print(err.mapError((_) => "Mapping error")); // 映射失败值的错误

    print("\n`mapBoth`");
    print(ok.mapBoth(
      success: (_) => "Mapping a success value", // 映射成功值
      failure: noop, // 映射失败值,不会执行
    ));
    print(err.mapBoth(
      success: noop, // 映射成功值,不会执行
      failure: (_) => "Mapping a failure value", // 映射失败值
    ));
  }

  /// 展示如何基于 `Result` 的结果执行代码块
  void on() {
    print("\n`on`");
    ok.onSuccess((_) => print("onSuccess")).onFailure(noop); // 成功时执行
    err.onSuccess(noop).onFailure((_) => print("onFailure")); // 失败时执行
  }

  /// 展示另一种基于 `Result` 的结果执行代码块的方式
  void when() {
    print("\n`when`");
    ok.when(
      success: (_) => print("When [success]"), // 成功时执行
      failure: noop, // 失败时不会执行
    );
    err.when(
      success: noop, // 成功时不会执行
      failure: (_) => print("When [failure]"), // 失败时执行
    );
  }

  /// 展示如何安全地调用方法,并将任何异常转换为 `Result` 错误
  void catching() {
    print("\n`runCatching`");
    print(runCatching(() => DateTime.now())); // 正常执行
    print(runCatching(() => throw DateException())); // 捕获异常并转换为 `Result` 错误
  }

  /// 展示如何根据空值将任何对象转换为 `Result`
  void toResult() {
    print("\n`toResult`");
    print(DateTime.now().toResultOr(() => DateException())); // 非空值转换为 `Ok`
    print(null.toResultOr(() => DateException())); // 空值转换为 `Err`
  }

  /// 展示如何处理 `Future` 类型的 `Result`
  Future<void> future() async {
    print("\n`Futures`");
    final futureOk = Future.value(ok); // Future<Result<DateTime, DateException>>
    final futureErr = Future.value(err); // Future<Result<DateTime, DateException>>

    await futureOk.when(success: (value) => print("Future(ok).when(success): $value"), failure: noop);
    await futureErr.when(success: noop, failure: (error) => print("Future(err).when(failure): $error"));

    await futureOk.onSuccess((value) => print("Future(ok).onSuccess: $value"));
    await futureErr.onSuccess(noop);

    await futureOk.onFailure(print);
    await futureErr.onFailure((error) => print("Future(err).onFailure: $error"));
  }

  // 调用所有示例方法
  instances();
  getters();
  map();
  on();
  when();
  catching();
  toResult();
  await future();
}

// 一个永远不会被调用的占位方法,用于演示目的
void noop(dynamic param) => print("A stub method that is never called; Used for demonstration purposes");

更多关于Flutter类型化结果处理插件typed_result的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter类型化结果处理插件typed_result的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用typed_result插件来进行类型化结果处理的示例代码。typed_result插件可以帮助你更好地管理异步操作的结果,特别是当你希望结果具有明确的类型时。

首先,确保你已经在pubspec.yaml文件中添加了typed_result依赖:

dependencies:
  flutter:
    sdk: flutter
  typed_result: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

接下来,让我们编写一些代码来演示如何使用typed_result

示例代码

  1. 创建一个异步函数,模拟一个网络请求或耗时操作
import 'dart:async';

Future<TypedResult<String, String>> fetchData() async {
  // 模拟网络请求或耗时操作
  await Future.delayed(Duration(seconds: 2));

  // 假设这里可能成功返回一个字符串,或者失败返回一个错误信息
  bool success = true; // 你可以根据实际情况改变这个值来模拟成功或失败

  if (success) {
    return TypedResult.success("这是从服务器获取的数据");
  } else {
    return TypedResult.failure("请求失败,请稍后重试");
  }
}
  1. 在UI中处理这个结果
import 'package:flutter/material.dart';
import 'package:typed_result/typed_result.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Typed Result Demo'),
        ),
        body: Center(
          child: FutureBuilder<TypedResult<String, String>>(
            future: fetchData(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.waiting) {
                return CircularProgressIndicator();
              } else if (snapshot.hasError) {
                return Text('Error: ${snapshot.error}');
              } else {
                final result = snapshot.data;
                if (result?.isSuccess ?? false) {
                  return Text('Success: ${result.data}');
                } else {
                  return Text('Failure: ${result?.error ?? 'Unknown error'}');
                }
              }
            },
          ),
        ),
      ),
    );
  }
}

解释

  1. fetchData函数

    • 使用Future.delayed模拟网络请求或耗时操作。
    • 根据模拟的成功或失败条件,返回TypedResult.successTypedResult.failure
  2. UI部分

    • 使用FutureBuilder来异步获取fetchData的结果。
    • 根据snapshot.connectionState判断当前状态(等待、完成、错误)。
    • 如果结果是成功的,显示成功数据;如果结果是失败的,显示错误信息。

通过这种方式,你可以使用typed_result插件来更清晰地处理异步操作的结果,使得代码更具可读性和可维护性。

回到顶部