Menu
Coddy logo textTech

Основы Streams

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 77 из 110.

В то время как Future предоставляет одно значение, Stream предоставляет последовательность значений с течением времени. Представьте его как трубу, которая может выдавать несколько фрагментов данных — это идеально подходит для событий, обновлений в реальном времени или обработки данных по частям.

Вы можете создать простой поток, используя Stream.fromIterable() или асинхронную функцию-генератор с async* и yield:

Stream<int> countToThree() async* {
  yield 1;
  yield 2;
  yield 3;
}

Future<void> main() async {
  await for (var number in countToThree()) {
    print(number);
  }
}
// Вывод: 1, 2, 3

Ключевое слово async* помечает функцию, которая возвращает Stream, а yield выдает каждое значение. Чтобы использовать поток, используйте await for, который обрабатывает каждое значение по мере его поступления.

Вы также можете прослушивать поток с помощью метода listen(), который принимает функцию обратного вызова:

Stream<String> greetings() async* {
  yield 'Hello';
  yield 'Hi';
  yield 'Hey';
}

void main() {
  greetings().listen((message) {
    print(message);
  });
}

Ключевое отличие от Futures: Future завершается один раз с единственным значением, в то время как Stream может выдавать множество значений до своего завершения. Это делает Streams идеальными для обработки непрерывных данных, таких как взаимодействие с пользователем, показания датчиков или данные, поступающие частями.

challenge icon

Задание

Легко

Давайте создадим систему таймера обратного отсчета, которая передает значения с течением времени с помощью потоков (streams)! Вы создадите класс, который генерирует последовательность чисел обратного отсчета, демонстрируя, как потоки доставляют несколько значений, а не только одно.

Вы организуете свой код в двух файлах:

  • countdown.dart: Создайте класс Countdown, который генерирует потоки обратного отсчета. Ваш класс должен иметь:
    • Поле start (int), в котором хранится начальное число для обратного отсчета
    • Конструктор, принимающий начальное число
    • Метод countDown(), который возвращает Stream<int>. Используйте async* и yield для передачи чисел от start до 0 (включительно)
    • Метод countDownWithMessage(), который возвращает Stream<String>. Он должен передавать строки в формате 'T-minus [number]' для каждого числа от start до 1, а затем передать 'Liftoff!' в качестве финального значения
  • main.dart: Импортируйте файл с обратным отсчетом и продемонстрируйте работу обоих методов потока. Ваша функция main должна быть асинхронной (async) и:
    • Создавать экземпляр Countdown, начиная с 3
    • Выводить на печать 'Number countdown:'
    • Использовать await for для итерации по countDown() и вывода каждого числа
    • Выводить пустую строку
    • Выводить на печать 'Launch sequence:'
    • Использовать await for для итерации по countDownWithMessage() и вывода каждого сообщения

Обратите внимание, как каждый оператор yield передает значение через поток, а await for обрабатывает каждое значение по мере его поступления. В отличие от Future, который доставляет один результат, ваши потоки будут передавать несколько значений последовательно!

Ожидаемый результат:

Number countdown:
3
2
1
0

Launch sequence:
T-minus 3
T-minus 2
T-minus 1
Liftoff!

Шпаргалка

Stream доставляет последовательность значений с течением времени, в отличие от Future, который возвращает одно значение. Потоки (Streams) идеально подходят для обработки событий, обновлений в реальном времени или поэтапной обработки данных.

Создайте поток, используя функцию асинхронного генератора с async* и yield:

Stream<int> countToThree() async* {
  yield 1;
  yield 2;
  yield 3;
}

Используйте поток с помощью цикла await for:

Future<void> main() async {
  await for (var number in countToThree()) {
    print(number);
  }
}

Кроме того, можно использовать метод listen() с функцией обратного вызова:

void main() {
  greetings().listen((message) {
    print(message);
  });
}

Вы также можете создать поток из итерируемого объекта, используя Stream.fromIterable().

Попробуйте сами

import 'countdown.dart';

Future<void> main() async {
  // TODO: Создайте экземпляр Countdown, начиная с 3
  
  // TODO: Выведите 'Number countdown:'
  
  // TODO: Используйте await for для итерации по countDown() и выведите каждое число
  
  // TODO: Выведите пустую строку
  
  // TODO: Выведите 'Launch sequence:'
  
  // TODO: Используйте await for для итерации по countDownWithMessage() и выведите каждое сообщение
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование