抛出错误后如何保持生成器函数产生值?

时间:2019-06-27 14:18:00

标签: asynchronous dart

在Dart语言中,如何在生成器函数中创建错误同时保持其创建值?

import 'dart:math' show Random;

main() {
  sum20RandomNumbers().then((sum) {
    print("Sum: $sum");
  });
}

Future<double> sum20RandomNumbers() async {
  var randomStream = generateRandomNumbers().handleError((error) {
    print('Ignore large number: ${error}');
    // How can I ignore error here?
  });

  int count = 0;
  double sum = 0;
  await for (var n in randomStream) {
    print(n);
    sum += n;
    if (++count >= 20) // sum 20 numbers at most
      break;
  }
  return sum;
}

Stream<double> generateRandomNumbers([int seed]) async* {
  final random = Random(seed);
  while (true) {
    final nextDouble = random.nextDouble();
    if (nextDouble > 0.8) {
      throw Exception('$nextDouble');
      // how can I keep generating next random numbers?
    }
    yield nextDouble;
  }
}

上面的代码显示sum20RandomNumbers()的意图是精确地累加20个随机数,但是在生成器函数generateRandomNumbers()中引发异常后,它将停止。抛出错误后如何保持生成器函数产生值?

1 个答案:

答案 0 :(得分:1)

对于sync*函数,您不能这样做。

Iterable可以报告错误的唯一方法是抛出Iterator的{​​{1}}方法。为此,必须抛出moveNext方法。 抛出sync*函数时,它将终止函数的主体,这使该主体无法继续并产生更多值。

抛出sync*的函数也会发生同样的事情,但是在那里您也有不同的发出错误的方式。因为流可以将错误报告为流的一部分,所以有可能发出错误并继续,因此您只能通过 throwing 来做到。

async*

诀窍是Stream<double> generateRandomNumbers([int seed]) async* { final random = Random(seed); while (true) { final nextDouble = random.nextDouble(); if (nextDouble > 0.8) { yield* Future<double>.error(Exception('$nextDouble')).asStream(); continue; } yield nextDouble; } } 包含错误的流。您可以通过许多不同的方式来做到这一点。

yield*

yield* Future<double>.error(theError).asStream();

yield* () async* { throw theError; } ();

yield* (StreamController<double>()..addError(theError)..close()).stream; 类获得Stream协整器之前,按流未来是最简单,最易读的方法。