Am văzut până acum că, dacă dorim să executăm aceleași instrucțiuni de mai multe ori, fie le scriem de mai multe ori, fie creăm o funcție și o apelăm de mai multe ori. În cazul funcțiilor, am văzut că putem avea parametri astfel încât am putea avea variații asupra modului în care se execută instrucțiunile din corpul funcției.
Dar, aceste soluții au un impediment. Trebuie să știm exact de câte ori vrem să executăm acele instrucțiuni și fie să le scriem de atâtea ori, fie să apelăm de atâtea ori o funcție care le conține. Ce facem dacă nu știm exact de câte ori vrem să fie executate?
De exemplu, am putea dori să scriem cifrele unui număr. Vom avea, probabil, o instrucțiune care va scrie o cifră și un mecanism prin care acesta va fi apelată. Dar, în funcție de cât de mare este acel număr, numărul execuțiilor va varia. Pentru numărul 2457 instrucțiunea se va executa de patru ori, dar pentru 47 doar de două ori.
Am văzut în episodul VIII că pentru a determina ultima cifră a unui număr este suficient să calculăm restul împărțirii acelui număr la zece. Putem observa că, practic, printr-o împărțire întreagă (calcularea câtului împărțirii) la zece eliminăm acea cifră din număr. Restul împărțirii noului număr la zece ne va da penultima cifră a numărului inițial; o nouă împărțire întreagă la zece va elimina și această cifră. Continuăm până se termină cifrele, adică atâta timp cât rezultatul împărțirii la zece va fi mai mare decât zero.
Vom avea cifrele în ordine inversă, dar ne vom mulțumi cu acest lucru deocamdată; de asemenea, nu va funcționa pentru numere negative și nici pentru numărul zero (vom crede că nu există nicio cifră).
Limbajul Swift ne pune la dispoziție o construcție care permite executarea unui bloc de instrucțiuni atâta timp cât o anumită condiție este adevărată.
Instrucțiunea while
Dar, care este noua instrucțiune? Pentru a explica ce vrem să facem, am folosit cuvintele atâta timp; am spus că atâta timp cât o anumită condiție este îndeplinită vom efectua o anumită acțiune. Și în Swift vom folosi ceva similar; va fi în engleză, deci cuvântul va fi while. El va fi urmat de condiția care trebuie verificată și de blocul de instrucțiuni care trebuie executate cât timp condiția este îndeplinită. Condiția este o expresie booleană; poate fi o simplă variabilă sau o expresie mai complexă. O astfel de instrucțiune este numită iterativă. Mai sunt folosite și denumirile de instrucțiune repetitivă sau buclă. Instrucțiunile executate atâta timp cât este îndeplinită condiția sunt numite și corpul buclei.
Putem scrie acum secvența care afișează cifrele unui număr (în ordine inversă)...
1 2 3 4 5 |
var n = 2457 while n > 0 { println(n % 10) n /= 10 } |
Astfel de instrucțiuni pot apărea oriunde; de exemplu, ar putea fi parte a unui bloc de instrucțiuni (în interiorul unui alt while, al unui if, al unei funcții etc.). Să vedem cum facem o funcție care să afișeze cifrele unui număr:
1 2 3 4 5 6 7 |
func cifre(n: Int) { var nn = n while nn > 0 { println(nn % 10) nn /= 10 } } |
Nu putem modifica valoarea parametrului n, așadar i-am creat o copie.
Observăm că este posibil ca blocul de instrucțiuni care formează bucla să nu se execute niciodată în cazul în care condiția nu este îndeplinită la prima verificare. Acest lucru s-ar întâmpla dacă am apela funcția de mai sus transmițând ca argument un număr negativ sau zero.
De asemenea, trebuie să avem în vedere că în corpul buclei trebuie să existe la un moment dat ceva care afectează condiția care este evaluată. Altfel, aceasta va rămâne tot timpul adevărată (dacă a fost prima dată) și corpul său se va executa la infinit dacă nu este înterupt prin alt mecanisme (de exemplu printr-un return).
While în while
Am spus că instrucțiunea while poate apărea oriunde. De exemplu, ar putea fi parte a blocului de instrucțiuni al unei alte instrucțiuni while. Să încercăm să scriem un program care afișează tabla înmulțirii până la zece. Vom avea numerele de la unu la zece ca prim factor și, pentru fiecare dintre acestea, numerele de la unu la zece ca al doilea factor. Să vedem cum ar arăta o funcție care ar realiza acest lucru:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
func tablaInmultirii () { var factor1 = 1 while factor1 <= 10 { var factor2 = 1 while factor2 <= 10 { print("\t") print(factor1 * factor2) factor2++ } println() factor1++ } } |
Am separat valorile prin taburi pentru a le alinia puțin mai frumos. Așa cum există caracterul special pentru sfârșit de linie, există și un caracter special pentru tab; acesta este \t. Dacă este apelată funcția de mai sus, la ieșire vom avea ceva de genul:
1 2 3 4 5 6 7 8 9 10 |
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 |
Mai trebuie să observăm că variabila factor2 este declarată și utilizată în interiorul primei bucle. Domeniul de vizibilitate al acestei variabile este doar în blocul de instrucțiuni care formează corpul buclei; pentru fiecare execuție a corpului primei bucle, va fi declarată și utilizată o nouă variabilă, care nu are nicio legătură cu variabilele cu același nume declarate și utilizate în timpul execuțiilor anterioare sau ulterioare.
Instrucțiunea do while
Până acum secvențele noastre erau de genul: cât timp o anumită condiție este îndeplinită execută instrucțiunile următoare. Avem la dispoziție o variație: execută instrucțiunile următoare cât timp o anumită condiție este îndeplinită.
În noua variantă, executăm instrucțiunile și abia apoi verificăm dacă este îndeplinită condiția. Dacă este îndeplinită mai executăm odată instrucțiunile și tot așa cât timp este îndeplinită acea condiție. Observăm că în această situație vom executa corpul buclei cel puțin odată.
Noua instrucțiune începe cu do, urmat de instrucțiunea sau blocul de instrucțiuni care formează corpul buclei, de cuvântul while și de condiția care trebuie verificată la sfârșit, între paranteze. Să rescriem funcția care afișează cifrele unui număr:
1 2 3 4 5 6 7 |
func cifre(n: Int) { var nn = n do { println(nn % 10) nn /= 10 } while (nn > 0) } |
Observăm un efect interesant; datorită faptului că se va executa cel puțin odată corpul buclei, de data aceasta vom avea rezultatul corect și dacă apelăm funcția cu argumentul zero.
Ar trebui menționat faptul că începând cu versiunea a doua a limbajului Swift (inclusă în Xcode 7), instrucțiunea do while este redenumită în repeat while.
Va urma
În episodul următor vom prezenta o altă instrucțiune repetitivă care simplifică puțin codul în anumite situații.