You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将可能抛出异常的Stream<Foo>转换为Stream<Result<Foo>>?

如何将可能抛出异常的Stream转换为Stream<Result>?

要实现这个需求,我们可以利用Dart Stream的错误处理机制,把原始流里的正常数据包装成Result.success,同时捕获所有异常并包装成Result.error。最简洁且灵活的方式是通过扩展方法+StreamTransformer实现,既能复用逻辑,又能覆盖所有异常场景。

实现方案

1. 定义扩展方法

给Stream添加一个扩展方法,统一处理流的转换逻辑:

extension StreamResultExtension<T> on Stream<T> {
  Stream<Result<T>> toResultStream() {
    return transform(StreamTransformer.fromHandlers(
      // 处理每个正常数据流元素
      handleData: (data, sink) {
        try {
          // 若处理data时有潜在异常(比如解析、转换操作),可在此处添加逻辑
          sink.add(Result.success(data));
        } catch (e, stackTrace) {
          // 捕获元素处理过程中的异常,包装为Result.error
          sink.add(Result.error('处理数据失败: $e'));
          // 可选:打印栈信息用于调试
          // print('Stack trace: $stackTrace');
        }
      },
      // 捕获Stream本身抛出的错误(比如流内部的异常)
      handleError: (error, stackTrace, sink) {
        sink.add(Result.error('流异常: $error'));
        // print('Stack trace: $stackTrace');
      },
      // 流结束时关闭sink
      handleDone: (sink) => sink.close(),
    ));
  }
}

2. 核心逻辑说明

这个实现覆盖了两种异常场景:

  • 元素处理异常:处理单个流元素(比如解析Foo对象)时抛出的异常,会被try-catch捕获并转为Result.error。
  • 流本身的异常:如果原始Stream内部直接抛出异常(比如async*函数中throw),会被handleError捕获并转为Result.error。

3. 使用示例

假设我们有一个可能抛出异常的原始流:

class Foo {
  final String value;
  Foo(this.value);
}

// 模拟一个可能抛出异常的Stream
Stream<Foo> createRiskyStream() async* {
  yield Foo("有效数据1");
  // 模拟流内部抛出异常
  throw Exception("网络请求失败");
  yield Foo("永远不会到达的数据");
}

使用扩展方法转换并监听结果:

void main() {
  createRiskyStream().toResultStream().listen((result) {
    // 使用模式匹配处理Result类型
    switch (result) {
      case ResultSuccess(data: final foo):
        print("成功接收: ${foo.value}");
      case ResultError(message: final msg):
        print("错误接收: $msg");
    }
  });
}

输出结果

成功接收: 有效数据1
错误接收: 流异常: Exception: 网络请求失败

可选优化

  • 可以根据异常类型定制错误信息,比如区分FormatException、SocketException等,返回更精准的错误描述。
  • 若不需要处理单个元素的异常(原始流元素本身不会触发异常),可以简化为map+handleError的组合:
extension StreamResultExtension<T> on Stream<T> {
  Stream<Result<T>> toResultStream() {
    return this
        .map(Result.success)
        .handleError((error, _) => Result.error(error.toString()));
  }
}

内容的提问来源于stack exchange,提问作者Alex.F

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:51:14