Czym są generatory w Dart (sync* i async*) i jak działają?
sobes.tech AI
Odpowiedź od AI
Generatory w Dartzie to funkcje, które zwracają sekwencję wartości w miarę ich generowania, a nie cały wynik od razu. Używa się słów kluczowych sync* dla generatorów synchronicznych i async* dla asynchronicznych.
Generator synchroniczny (sync*)
Zwracają obiekt typu Iterable. Używają słowa kluczowego yield do emitowania kolejnej wartości. Strumień wykonania jest wstrzymywany do momentu, gdy zostanie poproszona o następną wartość (np. w pętli for-in).
Iterable<int> countUpTo(int max) sync* {
for (int i = 1; i <= max; i++) {
yield i; // Emitowanie wartości
}
}
Generator asynchroniczny (async*)
Zwracają obiekt typu Stream. Używają słowa kluczowego yield do emitowania kolejnej wartości. Używają także yield*, aby emitować wszystkie wartości z innego Stream. Strumień wykonania jest wstrzymywany i wznawiany, gdy pojawi się nowe zdarzenie asynchroniczne.
Stream<int> countUpToAsync(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(Duration(milliseconds: 100)); // Symulacja pracy asynchronicznej
yield i; // Emitowanie wartości
}
}
Jak działają:
Po wywołaniu funkcji generatora, ciało funkcji nie jest od razu wykonywane. Zwracany jest obiekt (zarówno Iterable, jak i Stream). Rzeczywiste wykonanie ciała zaczyna się dopiero, gdy spróbujemy uzyskać wartość po raz pierwszy. Gdy osiągnięte zostanie słowo kluczowe yield, wartość jest przekazywana "na zewnątrz", a stan funkcji jest zapisywany. Wykonanie ciała jest wstrzymane. Przy następnym próbie uzyskania wartości, wykonanie jest wznawiane z miejsca, w którym zostało zatrzymane, aż do następnego yield lub końca funkcji.
Różnice:
| Cecha | sync* (Synchronous) | async* (Asynchronous) |
|---|---|---|
| Typ zwracany | Iterable |
Stream |
| Słowa kluczowe | sync*, yield |
async*, yield, yield* |
Użycie await |
Nie można | Można |
| Wstrzymanie | Do żądania następnej wartości | Do pojawienia się kolejnego zdarzenia asynchronicznego |