Menu
Coddy logo textTech

Iterable e Iterator

Fa parte della sezione Programmazione orientata agli oggetti del percorso Dart di Coddy. Lezione 68 di 110.

Ogni volta che usi un ciclo for-in su una List, un Set o un’altra raccolta, stai lavorando con Iterable e Iterator dietro le quinte. Comprendere questi concetti ti permette di creare classi personalizzate su cui è possibile eseguire un ciclo.

Un Iterable è qualsiasi oggetto in grado di produrre una sequenza di valori. Ha un requisito fondamentale: un getter iterator che restituisce un Iterator. È l'Iterator che scorre effettivamente gli elementi uno per uno:

var numbers = [1, 2, 3];
var iterator = numbers.iterator;

while (iterator.moveNext()) {
  print(iterator.current);  // 1, poi 2, poi 3
}

Il metodo moveNext() avanza all'elemento successivo e restituisce true se ce n'è uno, oppure false quando è terminato. La proprietà current ti fornisce l'elemento corrente.

Per rendere iterabile una tua classe, implementa l'interfaccia Iterable:

class Countdown extends Iterable<int> {
  final int start;
  Countdown(this.start);
  
  @override
  Iterator<int> get iterator => CountdownIterator(start);
}

class CountdownIterator implements Iterator<int> {
  int _current;
  
  CountdownIterator(int start) : _current = start + 1;
  
  @override
  int get current => _current;
  
  @override
  bool moveNext() {
    if (_current > 0) {
      _current--;
      return true;
    }
    return false;
  }
}

void main() {
  for (var n in Countdown(3)) {
    print(n);  // 3, 2, 1, 0
  }
}

Ora Countdown funziona con i cicli for-in e tutti i metodi Iterable come map, where e fold. Questo schema è essenziale quando crei collezioni personalizzate che si integrano perfettamente con l’ecosistema di collezioni di Dart.

challenge icon

Sfida

Facile

Costruiamo un generatore di intervalli personalizzato su cui è possibile iterare usando un ciclo for-in! Creerai le tue classi Iterable e Iterator per generare una sequenza di numeri entro un intervallo specificato.

Organizzerai il codice in due file:

  • range.dart: Crea due classi che collaborano per produrre una sequenza di numeri:
    • Una classe RangeIterator che implementa Iterator<int>. Deve tenere traccia della posizione corrente e sapere quando fermarsi. L’iteratore inizia prima del primo elemento, quindi è necessario chiamare moveNext() prima di accedere a current.
    • Una classe Range che estende Iterable<int>. Accetta un valore start e un valore end nel costruttore e fornisce un getter iterator che restituisce un RangeIterator.
    L’intervallo deve includere sia start sia end. Per esempio, Range(1, 5) deve produrre: 1, 2, 3, 4, 5.
  • main.dart: Importa il file dell’intervallo e mostra il tuo iterabile personalizzato:
    • Crea un Range(1, 5) e usa un ciclo for-in per stampare ogni numero su una riga separata
    • Stampa una riga vuota
    • Crea un Range(10, 13) e usa il metodo map per raddoppiare ogni valore, quindi stampa la lista risultante

Poiché la tua classe Range estende Iterable, ottiene automaticamente accesso a tutti i potenti metodi delle collezioni, come map, where e fold: ecco la bellezza di implementare l’interfaccia Iterable!

Output previsto:

1
2
3
4
5

[20, 22, 24, 26]

Provalo tu

import 'range.dart';

void main() {
  // TODO: Crea un Range(1, 5) e usa un ciclo for-in per stampare ogni numero
  
  
  // TODO: Stampa una riga vuota
  
  
  // TODO: Crea un Range(10, 13), usa map per raddoppiare ogni valore e stampa la lista
  
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Dart online