Utilizzando le strutture iterative è possibile ripetere l'esecuzione di un blocco di codice Perl per un certo numero di volte senza doverlo sempre riscrivere. Il numero di iterazioni è essenzialmente determinato da due fattori: esso può essere fisso (cioè predeterminato) oppure arbitrario, deciso dall'avverarsi o meno di una condizione. La struttura iterativa più nota era anche l'unica presente nei primi linguaggi di programmazione. Essa prevede l'impiego dell'istruzione for. Vediamone subito un esempio:
for ($i = 0; $i <= 3; $i++) {
print "2 x $i = ".(2*$i)."\n";
}
Questo scampolo di codice esegue un certo numero di volte, per la precisione 4, la riga contenuta tra le parentesi graffe. L'output del programma sarà:
2 x 0 = 0
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
e cioè la stampa degli operandi e del risultato della moltiplicazione di 2 per un numero che va da 0 a 4. Questo numero è il valore della variabile $i, detta variabile di controllo del ciclo; esso cambia ad ogni ripetizione del ciclo, incrementandosi sempre di una unità.
L'istruzione for accetta infatti, tra parentesi, tre parametri: il primo definisce il valore iniziale della variabile di controllo (0 in questo caso), il secondo rappresenta la condizione necessaria per l'esecuzione del blocco di istruzioni interno (il ciclo viene eseguito fino a che tale condizione risulta essere vera, in questo caso finché $i è minore o uguale a tre), il terzo indica invece la variazione da apportare alla variabile di controllo (incremento di una unità in questo esempio). Se si volessero invece saltare tutti i numeri dispari si potrebbe scrivere:
for ($i = 0; $i <= 3; $i = $i+2) {
print "2 x $i = ".(2*$i)."\n";
}
Se l'incremento che si desidera dare a $i è sempre una unità, esiste una forma più semplice di for, che prevede come parametri il solo numero iniziale e quello finale. Essa prevede l'utilizzo dell'operatore "..", già studiato in relazione agli array.
for $i(0..3) {
print "2 x $i = ".(2*$i)."\n";
}
Il while è l'altra fondamentale struttura iterativa. Vediamo come trasformare il ciclo for di cui sopra in un blocco while:
$i = 0;
while ($i <= 3) {
print "2 x $i = ".(2*$i)."\n";
$i++;
}
La variabile $i va in questo caso impostata al valore iniziale fuori dalla parte iterativa. Tutto ciò che fa while è valutare se una condizione è vera o falsa e continuare ad eseguire il ciclo finché essa risulta essere vera. In questo caso viene utilizzata $i, che però non è una variabile di controllo come nel ciclo for: la sua presenza è del tutto indifferente a while, ed infatti essa va gestita manualmente: il suo incremento in questo caso è ottenuto tramite la riga $i++ inserita nel blocco di istruzioni interno al ciclo iterativo. Come il significato logico di if era ribaltabile con unless, quello di while è a sua volta invertibile utilizzando until. Il codice appena scritto diventerebbe in questo caso:
$i = 0;
until ($i > 3) {
print "2 x $i = ".(2*$i)."\n";
$i++;
}
In altre parole l'esecuzione di while termina quando la condizione è falsa, mentre l'esecuzione di until s'interrompe quando la condizione risulta vera. Una forma un tantino diversa di queste due istruzioni permette di far sì che il ciclo venga comunque eseguito una volta prima che la condizione venga testata:
$i = 0;
do {
print "2 x $i = ".(2*$i)."\n";
$i++;
} while $i <= 3;
Senza utilizzare il do, se la condizione è falsa in partenza (poniamo che $i sia impostato ad esempio a 10), il ciclo non viene mai eseguito: con do si ha invece almeno una iterazione in ogni caso.
L'esecuzione del blocco all'interno delle strutture iterative può anche essere controllata direttamente da tale codice, senza intervenire sulla condizione, grazie a last, next e redo. La prima istruzione, già vista per quanto riguarda SWITCH, causa l'immediata interruzione dell'esecuzione del ciclo, con conseguente passaggio del controllo alla prima riga posta sotto di esso. Le seconde due causano l'immediata interruzione dell'esecuzione dell'iterazione corrente e la ripresa del ciclo dall'inizio. Tra le due istruzioni c'è una sottile ma importantissima differenza: con next la condizione viene valutata nuovamente, con redo no. In un ciclo for questo comporta che utilizzando la prima istruzione la variabile di controllo venga incrementata, cosa che non avviene se si è invece usato redo. Vediamo qualche riga di esempio: un esempio di tutto questo è visibile in Listato 1.
$ok = 0; # Definita per evitare il loop infinito
for ($i = 0; $i <= 3; $i++) {
# Salta 0
if ($i == 0) { next; }
# Se $i == 2 esce
if ($i == 2) { last; }
# Stampa
print "2 x $i = ".(2*$i)."\n";
# Se $i == 1 ripete (stampa due volte)
# a meno che $ok == 1
if (($i == 1) && ($ok == 0)) { $ok=1; redo; }
}
L'output di questo programma sarà: dunque:
2 x 1 = 2
2 x 1 = 2
Qualcuno avrà a questo punto intuito che è ad esempio possibile implementare un if utilizzando un while. Ad esempio:
if ($a == 1) { print "a vale 1\n"; }
può tranquillamente diventare:
while ($a == 1) { print "a vale 1\n"; last; }
Quanto appena scritto dimostra solamente ancora una volta che ci sono molti metodi per ottenere il risultato che si cerca:, si tratta solo di saper scegliere quello più adatto alla situazione. Sostituire un if con un while non è mai una buona idea: oltre ad essere inelegante, è meno efficiente.
|