Am arătat în episodul anterior cum putem face în așa fel încât să executăm în mod repetat instrucțiuni atâta timp cât o condiție este îndeplinită. Să considerăm acum un exemplu simplu: dorim să scriem o funcție care să afișeze toate numerele naturale cuprinse între 1 și o valoare pe care o primește ca parametru. Destul de simplu, nu? Ar fi cam așa:
1 2 3 4 5 6 7 |
def numere(n: Int): Unit = { var i = 1 while (i <= n) { println(i) i += 1 } } |
Dacă privim cu atenție codul, identificăm patru componente: în linia 2 avem inițializarea unei variabile; în linia 3 avem condiția (influențată și de variabila menționată), în linia 4 avem instrucțiunea care realizează operație care dorim să fie repetată și în linia 5 avem o instrucțiune care modifică variabila pentru ca, la un moment dat, condiția să nu mai fie îndeplinită.
Acesta este un șablon atât de des întâlnit, încât limbajul Scala oferă o prescurtare.
Instrucțiunea for
De multe ori pornim cu o valoarea și vrem să ajungem la o alta incrementând cu 1 valoarea la fiecare pas. Noua instrucțiune ne permite să indicăm doar variabila, valoarea inițială și valoarea finală; valoarea variabilei va crește la fiecare iterație. Practic, avem cuvântul for, urmat o pereche de paranteze care conțin o variabilă urmată de semnul <- , de valoarea inițială, de cuvântul to și de valoare finală. Funcția noastră ar putea fi rescrisă astfel:
1 2 3 4 5 |
def numere(n: Int): Unit = { for (i <- 1 to n) { println(i) } } |
Folosind metoda aceasta variabila i va primi ca ultimă valoare, valoarea n. Avem și posibilitatea de a itera până la n dar fără a atinge această valoare:
1 2 3 4 5 |
def numere(n: Int): Unit = { for (i <- 1 until n) { println(i) } } |
În Scala, avem posibilitatea de a folosi un anumit pas când iterăm folosind instrucțiunea for. Acest lucru se realizează folosind cuvântul by urmat de dimensiunea pasului. Acestea se specifică după ultima valoare pe care ar trebui să o atingă variabila noastră. De exemplu, dacă am dori să tipărim toate numerele impare până la n, dar fără n, ar trebui să scriem un cod de felul:
1 2 3 4 5 |
def numereImpare(n: Int): Unit = { for (i <- 1 until n by 2) { println(i) } } |
Pasul poate fi și negativ. Astfel că, dacă am dori să afișăm numerele de la 1 la n în ordine descrescătoare am putea scrie o procedură astfel:
1 2 3 4 5 |
def descrescator(n: Int): Unit = { for (i <- n to 1 by -1) { println(i) } } |
For în for
Cum era de așteptat, în cadrul corpului buclei pot apărea orice fel de instrucțiuni, inclusiv un alt for. Până acum am spus că este permis if în if (episodul IV) sau while în while (episodul X). Ne putem imagina că este permis și pentru alte instrucțiuni: am putea avea do în do și, acum, for în for. De fapt, știm că nu trebuie să ne limităm doar la un nivel de imbricare (vă mai amintiți termenul?). Și... instrucțiunile nu trebuie să fie de același fel: nimic nu ne oprește să avem if în while în for în match în for. Nu ar fi prea bine să ajungem să avem așa ceva fiindcă am înțelege cu greu ce se întâmplă exact în zona respectivă, dar este posibil.
Dar, să revenim la for în for; e destul de simplu. Să scriem o funcție care afișează numerele puțin altfel; fiecare va fi reprezentat de niște steluțe, numărul acestora indicând valoarea numărului.
1 2 3 4 5 6 7 8 |
def numere(n: Int): Unit = { for (i <- 1 to n) { for (j <- 1 to i) { print("*") } println() } } |
Dacă am apela funcția cu argumentul 10, la ieșire s-ar scrie:
1 2 3 4 5 6 7 8 9 10 |
* ** *** **** ***** ****** ******* ******** ********* ********** |
În principiu, buclele imbricate sunt controlate de variabile diferite, chiar dacă o variabilă dintr-o buclă exterioară poate fi folosită într-una interioară. În cazul nostru, variabila i care controlează prima buclă este utilizată în condiția celei de-a doua.
Din nou, este important domeniul de vizibilitate al variabilelor.
Un for mai simplu
Scala ne mai permite și o altă modalitate de a exprima un for. Putem în cadrul aceluiași for să iterăm cu mai multe variabile deodată:
1 2 3 4 5 6 7 8 |
def numere(n: Int): Unit = { for ( i <- 1 to n; j <- 1 to i ) { println(i + " * " + j + " = " + (i * j)) } } |
Va urma
În următorul episod vom vedea cum putem afecta execuția "normală" a instrucțiunilor din interiorul buclelor.