Ce face sync* și yield
O funcție marcată sync* întoarce un Iterable. În corp, fiecare yield valoare; produce următorul element. Funcția nu rulează toată de la început: pornește când cineva parcurge rezultatul și se oprește la fiecare yield, până când este cerut elementul următor (evaluare leneșă).
Datorită acestui comportament, un generator poate descrie chiar și o secvență infinită (de exemplu toate numerele Fibonacci); iei din ea doar cât îți trebuie cu take sau takeWhile.
yield* produce, pe rând, toate elementele altui Iterable; este util pentru generatoare recursive (parcurgerea unui arbore). Același yield se folosește și în generatoarele asincrone async*, unde produce elementele unui Stream.
Exemple
Exemplul 1: Un generator simplu
Mesajele arată că funcția rulează pas cu pas, intercalat cu bucla care o parcurge.
Iterable<String> zileLucratoare() sync* {
print('(încep)');
yield 'luni';
yield 'marți';
yield 'miercuri';
print('(aproape gata)');
yield 'joi';
yield 'vineri';
}
void main() {
for (final zi in zileLucratoare()) {
print(zi);
}
}
Rezultat
(încep)
luni
marți
miercuri
(aproape gata)
joi
vineri
Exemplul 2: Secvență infinită, folosită parțial
fibonacci nu se termină niciodată, dar take(10) cere doar primele 10 elemente.
Iterable<int> fibonacci() sync* {
var a = 0, b = 1;
while (true) {
yield a;
(a, b) = (b, a + b);
}
}
void main() {
print(fibonacci().take(10).toList());
print(fibonacci().where((x) => x.isEven).take(5).toList());
print(fibonacci().firstWhere((x) => x > 1000));
}
Rezultat
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
[0, 2, 8, 34, 144]
1597
Exemplul 3: yield* pentru un arbore
Generatorul recursiv parcurge toate folderele, la orice adâncime.
class Folder {
final String nume;
final List<Folder> subfoldere;
Folder(this.nume, [this.subfoldere = const []]);
Iterable<String> toateCaile([String prefix = '']) sync* {
final cale = '$prefix/$nume';
yield cale;
for (final sub in subfoldere) {
yield* sub.toateCaile(cale);
}
}
}
void main() {
final acasa = Folder('acasa', [
Folder('documente', [Folder('facturi'), Folder('cv')]),
Folder('poze', [Folder('vacanta-2025')]),
]);
acasa.toateCaile().forEach(print);
}
Rezultat
/acasa
/acasa/documente
/acasa/documente/facturi
/acasa/documente/cv
/acasa/poze
/acasa/poze/vacanta-2025
Greșeli frecvente
return valoare;într-un generator: nu este permis. Foloseșteyield; unreturn;fără valoare doar oprește generatorul.- Să crezi că generatorul a rulat când l-ai apelat: fără parcurgere (
for,toList), codul din el nu se execută deloc. - Parcurgerea de două ori a aceluiași
Iterablegenerat: generatorul rulează din nou de la început (și efectele lui se repetă).
Comenzi înrudite
async*: O funcție async* produce un Stream: trimite valori cu yield, în timp, și poate folosi await între ele.for-in: Parcurge pe rând elementele unei liste, unui set sau oricărui Iterable, fără indice.await for: Parcurge un Stream element cu element, așteptând fiecare eveniment; se termină când stream-ul se închide.funcții: Blocuri de cod cu nume, care primesc parametri și returnează o valoare; în Dart sunt și obiecte.