Generators in Dart are a powerful feature that allows you to produce a sequence of values lazily, meaning values are generated on demand rather than all at once. This can be particularly useful when working with large datasets or streams of data where you don't want to load everything into memory at once.
Key Concepts
- Synchronous Generators: These generate values synchronously using the
sync*keyword. - Asynchronous Generators: These generate values asynchronously using the
async*keyword. - Yield: The
yieldkeyword is used to produce a value in a generator function.
Synchronous Generators
A synchronous generator produces values one at a time and can be iterated over using a for loop or other iterable methods.
Example
Iterable<int> syncGenerator(int n) sync* {
for (int i = 0; i < n; i++) {
yield i;
}
}
void main() {
var numbers = syncGenerator(5);
for (var number in numbers) {
print(number);
}
}Explanation
- The
sync*keyword indicates that the function is a synchronous generator. - The
yieldkeyword is used to produce each value. - The
forloop in themainfunction iterates over the generated values.
Asynchronous Generators
An asynchronous generator produces values asynchronously, which is useful when dealing with I/O operations or other asynchronous tasks.
Example
Stream<int> asyncGenerator(int n) async* {
for (int i = 0; i < n; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void main() async {
await for (var number in asyncGenerator(5)) {
print(number);
}
}Explanation
- The
async*keyword indicates that the function is an asynchronous generator. - The
yieldkeyword is used to produce each value. - The
awaitkeyword is used to wait for asynchronous operations. - The
await forloop in themainfunction iterates over the generated values asynchronously.
Practical Exercises
Exercise 1: Fibonacci Sequence
Write a synchronous generator function that produces the first n numbers in the Fibonacci sequence.
Solution
Iterable<int> fibonacci(int n) sync* {
int a = 0, b = 1;
for (int i = 0; i < n; i++) {
yield a;
int temp = a;
a = b;
b = temp + b;
}
}
void main() {
var fibNumbers = fibonacci(10);
for (var number in fibNumbers) {
print(number);
}
}Exercise 2: Asynchronous Data Fetching
Write an asynchronous generator function that fetches data from a list of URLs and yields the data.
Solution
import 'dart:async';
Stream<String> fetchData(List<String> urls) async* {
for (var url in urls) {
await Future.delayed(Duration(seconds: 1)); // Simulate network delay
yield 'Data from $url';
}
}
void main() async {
var urls = ['url1', 'url2', 'url3'];
await for (var data in fetchData(urls)) {
print(data);
}
}Common Mistakes and Tips
- Forgetting
sync*orasync*: Ensure you usesync*for synchronous generators andasync*for asynchronous generators. - Blocking Code in Asynchronous Generators: Avoid blocking code in asynchronous generators; use
awaitfor asynchronous operations. - Using
yieldOutside Generators: Theyieldkeyword can only be used inside generator functions.
Summary
In this section, you learned about Dart generators, including both synchronous and asynchronous generators. You saw how to use the sync* and async* keywords to create generators and how to use the yield keyword to produce values. You also practiced writing generator functions with practical exercises. Understanding generators will help you handle sequences of data more efficiently, especially in scenarios involving large datasets or asynchronous operations.
Dart Programming Course
Module 1: Introduction to Dart
- Introduction to Dart
- Setting Up the Development Environment
- Your First Dart Program
- Basic Syntax and Structure
