În cadrul acestui episod vom introduce noțiunile de variabilă și tip de date și vom lucra cu numere și texte. Vom presupune că deja știți să utilizați un mediu de programare (fie el și online); dacă nu, vă recomandăm să citiți din nou episodul anterior.
Variabile
Chiar și pentru cele mai simple programe, la un moment dat avem nevoie să păstrăm anumite informații. Nu am avut nevoie de acest lucru atunci când doar am afișat un mesaj, dar atunci când am avut nevoie de numele utilizatorului a trebuit să păstrăm informația respectivă. Să ne amintim ultimul program de data trecută (puțin modificat):
1 2 3 4 |
object Main extends App { var nume: String = Console.in.readLine() println("Salut " + nume + "!") } |
Pe linia 2, avem o instrucțiune prin care preluăm informația introdusă de utilizator și o păstrăm în ceva de numit nume. Aceasta este o așa numită variabilă.
Variabilele pot fi văzute ca fiind niște recipiente care păstrează informații. Practic, cu ajutorul lor ajungem undeva în memoria calculatorului, luăm o mică parte din ea și îi dăm o denumire pentru a o putea folosi ulterior.
Avem nevoie de variabile pentru cele mai diverse scopuri. Dacă scriem un program care controlează un roboțel, vom avea nevoie de variabile care să conțină poziția acestuia, orientarea sa etc. În schimb, dacă programul nostru simulează un joc de fotbal, am avea nevoie de variabile pentru a păstra scorul.
În principiu, dacă trebuie să ținem minte ceva, cel mai simplu este să punem acel ceva într-o variabilă.
Majoritatea limbajelor moderne necesită declararea unei variabile înainte ca aceasta să poată fi utilizată. Scala este un astfel de limbaj. Mai mult, limbajul Scala ne permite să specificăm și ce tip de variabilă dorim. Putem alege să nu specificăm tipul, acesta putând fi determinat automat în anumite situații.
Dacă revenim la linia 2 a programului nostru, observăm că înaintea denumirii nume, apare cuvântul var. Acesta indică faptul că dorim să declarăm variabila nume. În continuare, această variabilă este urmată de cuvântul String. Acesta este tipul variabilei nume. Vom vedea exact ce înseamnă puțin mai încolo.
În Scala, pentru a declara o variabilă, folosim cuvântul var, după care precizăm denumirea variabilei iar în continuare, pentru a specificat tipul, punem caracterul : urmat de tipul variabilei. După care, în Scala, este necesar să ii atribuim variabilei o valoare inițială. Acest lucru face ca și în cazul atribuirii, folosind semnul = urmat de o valoare. Pentru un meci de fotbal, am putea avea o variabilă declarată astfel (ambele variante fiind echivalente):
1 |
var goluriGazde: Int = 0 |
sau
1 |
var goluriGazde = 0 |
Tipuri
În Scala toate variabilele au tipuri. În cazul în care alegem să nu specificăm tipul în momentul declarării, acesta este determinat din tipul valorii inițiale.
Tipul unei variabile indică ce fel de informație poate conține variabila respectivă. În exemplul nostru tipul este Int; el arată că variabila noastră este un număr întreg. Dacă o variabilă are un anumit tip, atunci informația conținută trebuie să fie compatibilă cu acel tip. Putem scrie:
1 |
var goluriGazde: Int = 2457 |
Chiar dacă este puțin probabil să găsim vreun sport în care o echipă să marcheze 2457 de goluri, instrucțiunea este corectă fiindcă, din punctul de vedere al calculatorului, goluriGazde este un număr întreg și valoarea sa poate fi orice număr întreg acceptabil (vom vedea mai încolo că există anumite restricții).
Totuși, nu putem scrie:
1 |
var goluriGazde: Int = "GInfo" |
GInfo este în acest caz un text (vom vedea puțin mai târziu rolul ghilimelelor) și variabila goluriGazde nu poate conține decât numere întregi. Dar, este perfect corect să scriem:
1 |
var goluriGazde = "GInfo" |
În acest caz tipul implicit este String. Pare ciudat și nu este deloc intuitiv. Ne-am așteptat ca ceva numit goluriGazde să fie un număr. Totuși, limbajul ne permite acest lucru. Trebuie să ne amintim că un calculator face ce îi spunem să facă, nu ce am vrea noi să facă.
Variabilele pot avea diverse tipuri: ele pot fi numere întregi, numere cu zecimale (acestea sunt denumite uneori numere reale, dar nu e chiar corect), texte etc. Dar putem avea și tipuri mult mai complexe; putem avea variabile care reprezintă clădiri, animale, galaxii, atomi și așa mai departe.
Unele tipuri sunt disponibile direct, altele trebuie inventate. Cele disponibile pot fi utilizate imediat; cele create deja de alții pot fi și ele utilizate. Dar, tipurile noi trebuie întâi definite.
Iată câteva exemple de declarații (împreună cu inițializările):
1 2 3 4 5 |
var a:Int = 5 var b:Double = 5.1 var c:Char = '+' var d:Boolean = true var s:String = "GInfo" |
Avem așadar un număr întreg a care are deocamdată valoarea 5, un număr cu zecimale b care are valoarea 5.1, un caracterc care are valoarea + și un așa numit boolean d cu valoarea true (adevărat), valorile booleene trebuie scrise în engleză și pot fi true sau false. În sfârșit, avem un șir de caractere s care conține textul GInfo.
Despre tipurile mai complicate vom discuta cu altă ocazie.
Numere
Am spus că în Scala există mai multe feluri de numere și chiar mai multe feluri de numere întregi. Știm că avem o infinitate de numere întregi. Pentru numere foarte mari, noi am nevoie să scriem multe cifre; la fel, calculatoarele ar avea nevoie să folosească tot mai multă memorie pe măsură ce numerele sunt mai mari. Dar, memoria calculatoarelor este finită. Diferitele variante de numere întregi ne spun cam câtă memorie dorim să utilizăm. Din acest motiv, pentru fiecare tip vom putea avea valori care nu depășesc o valoare maximă, specifică tipului. Semnul unui număr întreg e și el în memorie, deci putem avea și numere negative. Dar, datorită memoriei limitate, numerele trebuie să fie mai mari decât o valoare minimă specifică tipului.
Pare complicat și ciudat, dar nu e chiar așa. În practică nu utilizăm numere foarte mari. În cele mai multe situații este suficient tipul Int (valoarea maximă este 231 - 1, adică două miliarde și ceva). Uneori nu este suficient și avem nevoie de Long. Valoarea maximă este 263 - 1, adică aproape zece miliarde de miliarde. Dacă avem nevoie de valori și mai mari e mai complicat, dar sunt soluții.
Am văzut cum declarăm o variabilă și cum o inițializăm. Dar, am spus că valorile variabilelor se pot modifica. Pentru aceasta avem nevoie de o instrucțiune. O astfel de instrucțiune arată așa:
1 |
a = 2457 |
Valoarea variabilei a va fi acum 2457 indiferent care a fost înainte. Informația înlocuită se pierde. Nu vom ști cât a fost acea valoare înainte, deci dacă avem nevoie de ea, ar fi fost bine să o punem altundeva (într-o altă variabilă de exemplu).
Instrucțiunea anterioară este validă numai dacă a este într-adevăr o variabilă de tip numeric. Ea trebuie să fi fost declarată anterior (nu neapărat și inițializată).
Să nu credeți că a = 2457 este o ecuație sau ceva asemănător; este o comandă. Calculatorului i se spune ca în zona de memorie corespunzătoare variabilei a să fie pusă valoarea 2457. O astfel de comandă se numește atribuire.
Printr-o instrucțiune de atribuire, unei variabile i se dă o valoare. Tipul acestei valori trebuie să fie compatibil cu cel al variabilei (vom vedea ulterior de ce, în unele cazuri, e posibil ca tipurile să nu fie chiar identice).
Așadar, o instrucțiune de atribuire conține denumirea variabilei care va primi valoarea, urmată se semnul = și apoi de valoarea propriu zisă. În cazul nostru, valoarea a fost numărul 2457.
Există mai multe modalități de a reprezenta numerele; 2457 este varianta care ni se pare nouă naturală; nu e nicio șmecherie, e chiar numărul care urmează după 2456 și e înainte de 2458. Fără să explicăm de ce și doar pentru a arăta că se poate și altfel dacă chiar vrem, același număr poate fi reprezentat prin 0x999. Instrucțiunea următoare are exact același efect:
1 |
a = 0x999 |
În Scala, numerele sunt numere simple dacă nu apare nimic altceva lipit de ele. Alte simboluri sau caractere le modifică semnificația. Partea 999 din 0x999 nu reprezintă deloc numărul 999, dar nu e așa. Modalitatea de a specifica un număr sub forma 0999 nu este valabilă în Scala.
Lucrurile pot deveni și mai ciudate: 2, '2' și "2" sunt complet diferite. Primul este numărul 2, al doilea este un caracter care reprezintă cifra 2 și al treilea este un string. Mai multe despre caractere și string-uri în secțiunea următoare.
Numerele cu zecimale pot și ele fi reprezentate așa cum ni se pare nouă natural; 2.5 este o valoare corectă; dar, putem avea și ciudățenii ca 1e-4 sau 5D.
Nu dorim să explicăm aceste lucruri care par bizare; dorim doar să atragem atenția că în multe cazuri lucrurile nu sunt ceea ce par.
Caractere și string-uri
În Scala un caracter reprezintă un simbol. Poate fi o literă, o cifră, un semn de punctuație, un operator matematic etc. În Scala valoarea unui caracter este cuprinsă între apostroafe. În principiu, avem un apostrof, un semn și apoi un alt apostrof. De exemplu, caracterul + trebuie scris '+'.
Dar, ce ne facem dacă vrem să avem chiar valoarea apostrof? În Scala funcționează ca soluție varianta intuitivă '''. Ca urmare, instrucțiunea c = ''' este corectă. Mai funcționează, similar cu alte limbaje, și varianta în care putem marca al doilea apostrof cu un simbol special care să indice faptul că acesta nu trebuie interpretat ca sfârșit al descrierii caracterului, ci ca semn propriu-zis. Elementul special este \ (backslash). Această variantă se exprimă ca: c = '\''.
Ar părea că ni s-au rezolvat toate problemele, dar… dacă avem nevoie fix de backslash? c = '\' nu e corect fiindcă backslash-ul indică faptul că următorul element trebuie interpretat ca fiind semnul apostrof. Soluția este să marcăm semnul backslash cu un alt backslash. Deci, pentru a atribui unei variabile valoarea \, va trebui să scriem:
1 |
c = '\\' |
String-urile sunt cuprinse între ghilimele. Ați ghicit probabil, dacă unul dintre caracterele string-ului este chiar ", avem o problemă. Probabil intuiți soluția, vom marca astfel de caractere cu backslash. Dispare problema cu apostroful (nu mai trebuie marcat) și este în continuare prezentă cea cu backslash-ul (trebuie și aici dublat).
Dar… avem probleme suplimentare. Spuneam că string-urile sunt folosite în special pentru a păstra valori care reprezintă texte. Și textele pot avea mai multe linii. Cum facem?
Dacă scriem:
1 2 3 |
s = "Gazeta de Informatică" |
vom vedea că nu e corect.
Avem conceptul de caracter special de sfârșit de linie. Dacă dorim să avem textul Gazeta de Informatică scris pe trei rânduri (câte un cuvânt pe o linie), vom scrie:
1 |
s = "Gazeta\nde\nInformatică" |
Totuși, avem o alternativă. Dacă folosim trei ghilimele la începutul și la sfârșitul textului, atunci putem folosi mai multe linii. Iată un exemplu:
1 2 3 |
s = """Gazeta de Informatică""" |
Dar, pentru a complica puțin lucrurile, prezența acestei construcții """ face ca backslash-ul să nu mai aibă un rol special în interiorul textului. Este tratat ca fiind un simbol normal. Ajungem să avem din nou probleme cu ghilimelele. De exemplu, """\"""" nu mai este valid. Din fericire, ni se oferă o soluție. Textul pe mai multe linii poate conține în interior " dar nu mai mult de două simboluri " consecutive. Soluția noastra devine, deși pare ciudat, """"""" (7 simboluri " consecutive).
Va urma
În cadrul episodului următor vom prezenta detalii referitoare la modul în care sunt efectuate operațiile (nu neapărat matematice) și vom vedea ce sunt și la ce sunt folosite comentariile.