Функции генератора дротиков используются для ленивой генерации последовательности значений по запросу. Такая последовательность значений может создаваться синхронно или асинхронно. Для поддержки обоих сценариев доступны два типа встроенных функций генератора:

Синхронный генератор: функция синхронного генератора возвращает Итерационный объект. Это означает, что сначала значения генерируются, а затем функция лениво возвращается по запросу.

Итерируемый: набор значений или «элементов», к которым можно обращаться последовательно.

Асинхронный генератор: функция асинхронного генератора возвращает объект Stream. Последовательность значений создается по запросу, когда они становятся доступными.

Поток: источник событий с асинхронными данными.

Видео на YouTube

Давайте разберемся с функциями генератора на примере. Мы будем генерировать числа, начиная с заданного числа, скажем от 5 до 0, используя функции генератора. Мы рассмотрим оба способа (асинхронный и синхронный генераторы) для создания этой числовой последовательности.

Использование sync* - синхронного генератора

Функция Iterable<int> countDownFromSync(int num) sync* принимает номер как num и отправляет все числа, начиная с num и заканчивая 0. Функция синхронного генератора отмечена sync*. Значения возвращаются с использованием ключевого слова yield. Итерируемый sequence получает числовую последовательность и распечатывает каждое число с помощью цикла for. Эта числовая последовательность фактически не создается до тех пор, пока к ней не обращается for цикл.

main1 ():

void main1() {
  print("Getting CountDown Iterable [sync* + yield]");
  Iterable<int> sequence = countDownFromSync(5);

  print("Starting...");

  for (int value in sequence) {
    print(value);
  }
  print("DONE");
}

//sync*
Iterable<int> countDownFromSync(int num) sync* {
  while (num > 0) {
    yield num--;
  }
}

Вывод:

sync* помогает генерировать значения синхронным образом. Обратите внимание, что сообщение Starting... печатается перед выполнением цикла. Наконец-то выполняется сообщение DONE.

Getting CountDown Iterable [sync* + yield]
Starting...
5
4
3
2
1
DONE

Использование async* - асинхронного генератора

Функция Stream<int> countDownFromAsync(int num) async* принимает номер как num и доставляет номерную последовательность, начиная с num до 0. Функция асинхронного генератора помечена async*. Значения возвращаются с использованием ключевого слова yield. Поток sequence получает числовую последовательность. Доступ к его значениям можно получить, как только он начал прослушивание.

main2 ():

void main2() {
  print("Getting CountDown Stream [async* + yield]");
  Stream<int> sequence = countDownFromAsync(5);

  print("Starting...");

  sequence.listen((int value) {
    print(value);
  });
  print("DONE");
}

//async*
Stream<int> countDownFromAsync(int num) async* {
  while (num > 0) {
    yield num--;
  }
}

Вывод:

async* помогает генерировать значения асинхронным образом. Обратите внимание, что сообщения / настройки Starting... и DONE печатаются до того, как будут напечатаны фактические значения потока. Значения печатаются по мере того, как они становятся доступными после кода настройки.

Getting CountDown Stream [async* + yield]
Starting...
DONE
5
4
3
2
1

Использование sync* + yield* - Рекурсивный синхронный генератор

Когда функции генератора используются рекурсивно, yield* используется для обозначения таких рекурсивных вызовов функций. В этом примере показано, как рекурсивно использовать функции генератора. Вы заметите тот же результат, что и для нерекурсивной реализации. Ключевое слово yield* используется для функции, вызываемой рекурсивно.

void main3() {
  print("Getting CountDown Iterable [sync* + yield*]");
  Iterable<int> sequence = countDownFromSyncRecursive(5);

  print("Starting...");

  for (int value in sequence) {
    print(value);
  }
  print("DONE");
}

//sync* + yield* for recursive functions
Iterable<int> countDownFromSyncRecursive(int num) sync* {
  if (num > 0) {
    yield num;

    yield* countDownFromSyncRecursive(num - 1);
  }
}

Вывод:

Getting CountDown Iterable [sync* + yield*]
Starting...
5
4
3
2
1
DONE

Использование async* + yield* - Рекурсивный асинхронный генератор

Это пример рекурсивного использования функции асинхронного генератора. Он также имеет тот же вывод, что и его нерекурсивный аналог.

void main4() {
  print("Getting CountDown Stream [async* + yield*]");
  Stream<int> sequence = countDownFromAsyncRecursive(5);

  print("Starting...");

  sequence.listen((int value) {
    print(value);
  });
  print("DONE");
}

//async* + yield* for recursive functions
Stream<int> countDownFromAsyncRecursive(int num) async* {
  if (num > 0) {
    yield num;

    yield* countDownFromAsyncRecursive(num - 1);
  }
}

Вывод:

Getting CountDown Stream [async* + yield*]
Starting...
DONE
5
4
3
2
1

Резюме

В этой статье мы увидели, как использовать функцию генератора Дарта для синхронного и асинхронного создания последовательности значений по запросу итеративным и рекурсивным образом.

Это все для этой статьи. Прочтите Dart Vocabulary Series, чтобы узнать о других материалах по Dart.

Исходный код

Пожалуйста, проверьте исходный код на Github здесь.

использованная литература

  1. Языковой тур по дартсу
  2. За пределами асинхронного режима
  3. Генераторы-флаттер в фокусе

Happy Darting :)

_ Понравилась статья? Не нашли интересную тему? Пожалуйста, оставьте комментарий или напишите в twitter о темах, которыми вы хотите, чтобы я поделился!

Кстати, я люблю и кексы, и кофе :) _

Следуй за мной в Medium

Первоначально опубликовано на https://ptyagicodecamp.github.io 7 июня 2020 г.