Как сохранить функцию генератора, выдающую значения после выдачи ошибки? - PullRequest
1 голос
/ 27 июня 2019

На языке дартов, как я могу создать ошибку в функции генератора, сохраняя при этом создание значений?

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 Ответ

1 голос
/ 03 июля 2019

Вы не можете сделать это для sync* функций.

Единственный способ, которым Iterable может сообщить об ошибке, - это вызвать метод Iterator 'moveNext.Чтобы сделать это, метод sync* должен бросить.Когда функция sync* выдает, она завершает тело функции, что делает невозможным продолжение этого тела и получение большего количества значений.

То же самое происходит с 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 не получит Stream.error cosntructor, будущее как поток - самый простой и читаемый подход.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...