Flutter安全结果处理插件safe_result的使用

Flutter 安全结果处理插件 safe_result 的使用

safe_result 是一个 Dart 包,它提供了一种类型安全的方式来处理成功和错误情况,并支持自定义错误类型。

特性

  • 类型安全的错误处理,支持自定义错误类型
  • 支持模式匹配
  • 功能编程工具
  • 支持异步操作
  • 支持空安全
  • 支持泛型错误类型,以提高错误处理能力

开始使用

pubspec.yaml 文件中添加依赖:

dependencies:
  safe_result: ^2.0.1

使用示例

基本用法

import 'package:safe_result/safe_result.dart';

// 定义自定义错误类型
sealed class AppError {
  final String message;
  const AppError(this.message);

  @override
  String toString() => message;
}

class ValidationError extends AppError {
  const ValidationError(super.message);
}

class NetworkError extends AppError {
  final int statusCode;
  const NetworkError(super.message, this.statusCode);

  @override
  String toString() => '$message (Status: $statusCode)';
}

void main() {
  // 创建带有特定错误类型的 Result 对象
  final success = Result<int, ValidationError>.ok(42);
  final failure = Result<int, ValidationError>.error(
      ValidationError('Value must be positive'));

  // 检查结果类型
  print('Is success? ${success.isOk}'); // true
  print('Is failure? ${failure.isError}'); // true

  // 获取值
  final value = success.getOrElse(0);
  print('Value or default: $value'); // 42

  final fallback = failure.getOrElse(0);
  print('Fallback value: $fallback'); // 0
}

模式匹配

// 使用 switch 表达式进行模式匹配
Result<String, ValidationError> processInput(String input) => switch (input) {
  '' => Result.error(ValidationError('Input cannot be empty')),
  var str when str.length < 3 =>
    Result.error(ValidationError('Input too short')),
  var str => Result.ok(str.toUpperCase())
};

// 使用 switch 语句处理结果
void handleResult(Result<String, ValidationError> result) {
  switch (result) {
    case Ok(value: final v):
      print('Success: $v');
    case Error(error: final e):
      print('Error: $e');
  }
}

handleResult(processInput('')); // Error: Input cannot be empty
handleResult(processInput('hi')); // Error: Input too short
handleResult(processInput('hello')); // Success: HELLO

变换

final result = Result<int, ValidationError>.ok(42);

// 使用 map 方法对成功值进行变换
final doubled = result.map((value) => value * 2);
print(doubled); // Ok(84)

// 使用 fold 方法对值和错误类型进行变换
final networkResult = result.fold<String, NetworkError>(
  onOk: (value) => Result.ok('Success: $value'),
  onError: (error) => Result.error(NetworkError(error.toString(), 400)),
);
print(networkResult); // Ok(Success: 42)

// 处理错误情况
final failedResult = Result<int, ValidationError>.error(
  ValidationError('Invalid input'),
);

final transformedError = failedResult.fold<String, NetworkError>(
  onOk: (value) => Result.ok('Success: $value'),
  onError: (error) => Result.error(NetworkError(error.toString(), 400)),
);
print(transformedError); // Error: Invalid input (Status: 400)

// 使用不同错误类型的链式变换
final dbResult = result.map((value) => value * 2).fold<String, DatabaseError>(
  onOk: (value) => value > 50
      ? Result.ok('Large number: $value')
      : Result.error(DatabaseError('Number too small')),
  onError: (error) => Result.error(DatabaseError(error.toString())),
);
print(dbResult); // Ok(Large number: 84)

验证

class User {
  final String name;
  final int age;
  final String email;

  User(this.name, this.age, this.email);

  @override
  String toString() => 'User(name: $name, age: $age, email: $email)';
}

// 验证函数返回带有 ValidationError 的 Result
Result<String, ValidationError> validateName(String name) {
  if (name.isEmpty) {
    return Result.error(ValidationError('Name cannot be empty'));
  }
  if (name.length < 2) {
    return Result.error(ValidationError('Name too short'));
  }
  return Result.ok(name);
}

Result<int, ValidationError> validateAge(int age) {
  if (age < 0 || age > 120) {
    return Result.error(ValidationError('Invalid age'));
  }
  return Result.ok(age);
}

Result<String, ValidationError> validateEmail(String email) {
  final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
  if (!emailRegex.hasMatch(email)) {
    return Result.error(ValidationError('Invalid email format'));
  }
  return Result.ok(email);
}

// 结合多个验证
Result<User, ValidationError> createUser(String name, int age, String email) {
  final nameResult = validateName(name);
  final ageResult = validateAge(age);
  final emailResult = validateEmail(email);

  return switch ((nameResult, ageResult, emailResult)) {
    (Ok(value: final n), Ok(value: final a), Ok(value: final e)) =>
      Result.ok(User(n, a, e)),
    (Error(error: final e), _, _) => Result.error(e),
    (_, Error(error: final e), _) => Result.error(e),
    (_, _, Error(error: final e)) => Result.error(e),
  };
}

// 示例用法
final validUser = createUser('John', 30, 'john@example.com');
final invalidUser = createUser('', -5, 'invalid-email');

print(validUser); // Ok(User(name: John, age: 30, email: john@example.com))
print(invalidUser); // Error: Name cannot be empty

异步操作

Future<void> asyncExample() async {
  // 模拟异步操作并返回带有 NetworkError 的 Result
  Future<Result<String, NetworkError>> fetchUserName() async {
    try {
      // 模拟 API 调用
      await Future.delayed(Duration(seconds: 1));
      return Result.ok('John Doe');
    } catch (e) {
      return Result.error(NetworkError('Failed to fetch user', 500));
    }
  }

  Future<Result<int, NetworkError>> fetchUserAge(String userName) async {
    try {
      // 模拟 API 调用
      await Future.delayed(Duration(seconds: 1));
      return Result.ok(30);
    } catch (e) {
      return Result.error(NetworkError('Failed to fetch age', 404));
    }
  }

  // 使用 andThen 进行链式异步操作
  final result = await fetchUserName().andThen((name) => fetchUserAge(name));

  // 处理最终结果
  switch (result) {
    case Ok(value: final age):
      print('User age: $age');
    case Error(error: final e):
      print('Error: $e');
  }
}

错误处理最佳实践

  1. 定义领域特定的错误类型

    sealed class ApiError extends AppError { ... }
    sealed class DomainError extends AppError { ... }
    sealed class ValidationError extends AppError { ... }
    
  2. 使用错误类型的模式匹配

    switch (result) {
      case Error(error: NetworkError e) when e.statusCode == 404:
        print('Resource not found: ${e.message}');
      case Error(error: ValidationError e):
        print('Validation failed: ${e.message}');
      case Ok(value: final v):
        print('Success: $v');
    }
    
  3. 链式操作保持一致的错误类型

    Result<T, E> validateAndTransform<T, E extends AppError>(T input) {
      return validate(input)
          .map(transform)
          .fold(
            onOk: (value) => Result.ok(value),
            onError: (error) => Result.error(error),
          );
    }
    

更多关于Flutter安全结果处理插件safe_result的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

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


当然,以下是如何在Flutter项目中使用safe_result插件的详细代码示例。safe_result是一个用于安全处理异步结果的插件,它可以防止在结果未定义或为空时引发异常。

第一步:添加依赖

首先,你需要在pubspec.yaml文件中添加safe_result的依赖:

dependencies:
  flutter:
    sdk: flutter
  safe_result: ^最新版本号  # 请替换为实际最新版本号

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

第二步:使用SafeResult

下面是一个完整的Flutter应用示例,展示了如何使用safe_result插件来安全地处理异步结果。

main.dart

import 'package:flutter/material.dart';
import 'package:safe_result/safe_result.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Safe Result Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SafeResultDemo(),
    );
  }
}

class SafeResultDemo extends StatefulWidget {
  @override
  _SafeResultDemoState createState() => _SafeResultDemoState();
}

class _SafeResultDemoState extends State<SafeResultDemo> {
  final SafeResultController<String> _safeResultController = SafeResultController();

  @override
  void initState() {
    super.initState();
    // 模拟一个异步操作
    Future.delayed(Duration(seconds: 2), () {
      // 模拟成功结果
      _safeResultController.success("操作成功!");
      // 你可以根据需要调用_safeResultController.error("错误信息")来模拟错误
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Safe Result Demo'),
      ),
      body: Center(
        child: SafeResultBuilder<String>(
          controller: _safeResultController,
          loading: () => CircularProgressIndicator(),
          success: (result) => Text(
            '结果: $result',
            style: TextStyle(fontSize: 20, color: Colors.green),
          ),
          error: (error) => Text(
            '错误: $error',
            style: TextStyle(fontSize: 20, color: Colors.red),
          ),
          empty: () => Text(
            '结果为空',
            style: TextStyle(fontSize: 20, color: Colors.grey),
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _safeResultController.dispose();
    super.dispose();
  }
}

代码解释

  1. 添加依赖:在pubspec.yaml中添加safe_result依赖。

  2. 创建控制器:在_SafeResultDemoState中创建一个SafeResultController<String>实例,用于管理异步结果。

  3. 模拟异步操作:在initState中使用Future.delayed模拟一个异步操作,并在2秒后调用_safeResultController.success来设置成功结果。你也可以调用_safeResultController.error来模拟错误。

  4. 构建UI:使用SafeResultBuilder来构建UI,根据当前结果状态显示不同的Widget。

    • loading:显示加载指示器。
    • success:显示成功结果。
    • error:显示错误信息。
    • empty:显示空结果(可选,如果需要处理空结果)。
  5. 释放资源:在dispose方法中释放SafeResultController实例,以防止内存泄漏。

通过这种方式,你可以使用safe_result插件来安全地处理异步结果,避免在结果未定义或为空时引发异常。

回到顶部