Perl de învățare

Continuăm să studiem Perl. În acest capitol ne îndreptăm atenția către funcții. Funcțiile sunt blocuri de cod care sunt date cu nume, astfel încât să le putem folosi când este necesar. Funcțiile ajută la organizarea codului în fragmente ușor de înțeles. Acestea vă permit să creați un program pas cu pas, testați-l în deplasare.







După ce aveți ideea programului, trebuie să dezvoltați o schemă pentru construcția sa - în cap sau pe hârtie. Fiecare pas în schemă ar putea fi o funcție în programul dvs. Aceasta se numește programare modulară. Programarea modulară vă permite să ascundeți detaliile programului, îmbunătățind astfel lizibilitatea codului sursă al programului.

De exemplu, dacă programul dvs. conține o funcție care calculează zona unui cerc, linia următoare se poate referi la ea:

Privind apeluri de funcții similare, o persoană care citește codul sursă al programului tău înțelege ceea ce face programul tău. În același timp, el nu are nevoie să știe cum este implementată o anumită funcție. Prin urmare, este important să dăm funcțiile "vorbind" nume - astfel încât, după nume, să poată înțelege ce face funcția.

Apelarea funcției înseamnă că interpretul Perl din punctul de apel al funcției oprește executarea seriei curente de linii de cod și continuă executarea codului funcției. Când se termină codul funcției, interpretul revine la punctul de apel și continuă să execute programul din următoarea linie.

Să aruncăm o privire mai atentă la apelul funcției - mai întâi vedem o variabilă scalară, apoi operatorul de atribuire. Știți deja ce înseamnă asta - Perl atribuie valoarea $ areaOfFirstCircle în dreapta caracterelor de atribuire. Dar ce este cu adevărat în dreapta?

Primul lucru pe care îl vedeți este numele funcției areaOfCircle (). Parantezele din dreapta și absența lui $, @ și% în fața numelui caracterelor indică faptul că acesta este un apel pentru funcții. În interiorul parantezelor există o listă de parametri sau valori transmise funcției.

Calcularea zonei unui cerc:

$ areaOfFirstCircle = zonaOfCircle (5);
imprimare ("$ areaOfFirstCircle \ n");
sub-suprafațăOfCircle $ radius = $ _ [0];
întoarcere (3.1415 * (raza $ ** 2));
>

sub nume Funcția corpului funcției
>

Și asta e tot. Funcția dvs. este gata.

Situația este mai complicată cu parametrii. Parametrii sunt valorile pe care le trecem la funcție. Parametrii sunt conținute în paranteze imediat după numele funcției. În exemplul de mai sus, apelul funcției este areaOfCircle (5). Aici am folosit doar un singur parametru. Dar, chiar dacă funcția are doar un singur parametru, Perl, atunci când este apelat, creează o serie de parametri pentru utilizare de către funcție.

În interiorul funcției, matricea parametrilor este numită @_. Toți parametrii trecuți la funcții sunt conținute în matricea @, unde pot fi preluate dacă este necesar.

Funcția noastră mică din exemplul de mai sus ar putea face următoarea linie:

Această linie atribuie primul element al matricei @ la variabila scalară $ rază.

Dacă doriți, nu puteți folosi instrucțiunea returnare din funcție pentru a returna o valoare, - Perl va returna automat valoarea ultimei expresii evaluate. Dar va fi mai bine dacă utilizați în continuare declarația de returnare - pentru a evita multe erori aleatorii.

Poate că ați văzut în unele limbi de programare diferențele dintre subrutine și funcții. În astfel de limbi, funcția trebuie să returneze o valoare, în același timp, subrutina nu returnează o valoare. În Perl, acest lucru nu este - aveți doar o funcție - indiferent dacă returnează orice valoare sau nu.

Folosind o serie de parametri (@_)

Așa cum am menționat mai sus - toți parametrii funcției pot fi găsiți în matricea parametrilor @_. Acest lucru este foarte convenabil - pentru a afla câți parametri au fost transferați funcției, trebuie doar să accesați matricea parametrilor @_ într-un context scalar.

primulSub (1, 2, 3, 4, 5, 6);
firstSub (1 ... 3);
firstSub ("A" .. "Z");
sub primulSub $ numParameters = @_;
print ("Numărul de parametri este $ numParameters \ n");
>

Programul va tipări:

Numărul de parametri este de 6

Numărul de parametri este de 3

Numărul de parametri este de 26

Perl vă permite să transmiteți un număr de parametri funcției. Funcția însăși poate determina ce parametri să utilizeze și în ce ordine. O gamă de parametri @ _ poate fi folosită în același mod ca orice altă matrice.

Desigur, acest lucru nu este foarte convenabil - consultați parametrii transmiși funcției prin numerele lor - @_ [0] sau @_ [1]. Puteți utiliza o tehnologie mai convenabilă:

areaOfRectangle (2, 3);
areaOfRectangle (5, 6);
sub areaOfRectangle ($ înălțime, $ lățime) = @_;
$ area = $ înălțime * $ lățime;
print ("Înălțimea este $ înălțime, lățimea este $ lățime, zona este $ area. \ n \ n");
>

Înălțimea este 2. Lățimea este 3. Zona este de 6.

Înălțimea este 5. Zona este de 30.

Parcurgerea parametrilor funcției prin referință.

Dacă treceți într-o funcție nu un număr, ci o variabilă, atunci dacă schimbați valoarea în interiorul funcției, ea se modifică și pentru restul programului. Aceasta se numește parametru care trece prin referință.

@array = (0..5);
print ("Înainte de apelul fuNCtion, array = @array \ n");
firstSub (@array);
print ("După apelul fuNCtion, array = @array \ n");
sub primulSub $ _ [0] = "A";
$ _ [1] = "B";
>

Înainte de apelul fuNCtion, array = 0 1 2 3 4 5

După apelul fuNCtion, array = A B 2 3 4 5







După cum puteți vedea, funcția a modificat valoarea parametrilor care i-au fost transmise și aceasta a afectat și restul programului - valorile arrayului @array s-au schimbat nu numai pentru funcție, ci și pentru restul programului. Aceasta este o practică proastă de programare - dacă nu aveți un astfel de scop specific, atunci nu utilizați niciodată astfel de prema - acestea sunt pline de erori neobișnuite. Pe de altă parte, dacă atribuiți valorile parametrilor trecuți la variabilele noi (așa cum s-a arătat mai devreme) și lucrați numai cu ei la începutul funcției, nu veți avea o astfel de problemă - la urma urmei, în acest caz nu schimbați efectiv valorile funcțiilor transferate parametrii.

Iată un exemplu al aceluiași program, dar scris mai corect:

@array = (0..5);
print ("Înainte de apelul fuNCtion, array = @array \ n");
firstSub (@array);
print ("După apelul fuNCtion, array = @array \ n");
sub primulSub ($ firstVar, $ secondVar) = @_;
$ firstVar = "A";
$ secondVar = "B";
>

Înainte de apelul fuNCtion, array = 0 1 2 3 4 5

După apelul fuNCtion, array = 0 1 2 3 4 5

După cum puteți vedea, funcția atribuie valorile parametrilor transferați acesteia la variabilele noi și apoi operează numai cu ei, fără a schimba direct matricea de parametri.

Dar, atunci puteți întâlni o altă problemă:

$ firstVar = 10;
@array = (0..5);
print ("Înainte de apelul fuNCtion \ n");
print ("\ tfirstVar = $ firstVar \ n");
tipăriți ("\ tarray = @array \ n");
firstSub (@array);
print ("După apelul după fuNCtion \ n");
print ("\ tfirstVar = $ firstVar \ n");
tipăriți ("\ tarray = @array \ n");
sub primulSub ($ firstVar, $ secondVar) = @_;
$ firstVar = "A";
$ secondVar = "B";
>

Înainte de apelul fuNCtion
firstVar = 10
array = 0 1 2 3 4 5

După apelul fuNCtion
firstVar = A
array = 0 1 2 3 4 5

Aceasta este, în mod implicit, toate variabilele din programul Perl sunt accesibile din orice fragment de cod. Acest lucru este foarte convenabil în multe cazuri, dar deseori cauzează neplăceri și duce la erori neplăcute. În continuare, veți învăța cum să creați variabile care sunt vizibile numai în cadrul funcțiilor corespunzătoare.

Domenii de acțiune ale variabilelor.

Obiectul unei variabile este fragmentele de cod în care puteți utiliza această variabilă. În mod implicit, orice variabilă din programul Perl este "vizibilă" de oriunde din program.

Uneori este foarte util să se limiteze sfera de aplicare a unei variabile în cadrul unei funcții. În acest caz, modificarea valorii unei variabile în interiorul unei funcții nu va afecta în nici un fel restul programului. Perl are două funcții - my () și local (). Prima creează o variabilă care este vizibilă numai în interiorul acestei funcții. Cel de-al doilea creează o variabilă, care poate, de asemenea, "vedea" funcțiile solicitate din această funcție.

firstSub ("AAAAA", "BBBBB");
sub primeSub local ($ firstVar) = $ _ [0];
($ secondVar) = $ _ [1];
print ("firstSub: firstVar = $ firstVar \ n");
tipăriți ("firstSub: secondVar = $ secondVar \ n \ n");
secondSub ();
print ("firstSub: firstVar = $ firstVar \ n");
tipăriți ("firstSub: secondVar = $ secondVar \ n \ n");
>

sub secondSub print ("secondSub: firstVar = $ firstVar \ n");
print ("secondSub: secondVar = $ secondVar \ n \ n");
$ firstVar = "ccccC";
$ secondVar = "DDDDD";
print ("secondSub: firstVar = $ firstVar \ n");
print ("secondSub: secondVar = $ secondVar \ n \ n");
>

firstSub: firstVar = AAAAA
firstSub: secondVar = BBBBB
secondSub: firstVar = AAAAA
Utilizarea valorii neinitializate la linia test.pl 19.
secondSub: secondVar =
secondSub: firstVar = ccccC
secondSub: secondVar = DDDDD
firstSub: firstVar = ccccC
firstSub: secondVar = BBBBB

După cum puteți vedea, funcția secondSub () nu are acces la variabila $ secondVar, care a fost creată de funcția my () în interiorul funcției firstSub (). Perl transmite chiar și un mesaj, avertizându-vă despre asta. În același timp, variabila $ firstVar este disponibilă și poate fi modificată prin funcția secondSub ().

Dacă este posibil, încercați să utilizați numai funcția mea () și nu utilizați funcția locală () - deci va trebui să vă controlați mai strict domeniul de aplicare al variabilelor.

De fapt, meu () este mult mai complex și mai funcțional. Dar aceasta va fi discutată în Capitolul 15 - "Module Perl".

Vă amintiți care este diferența dintre parametrii funcției de trecere prin referință și valoare? Dacă transmiteți parametrii după valoare, atunci funcția nu poate modifica valorile parametrilor (variabilelor) care îi sunt transmise și, prin urmare, nu va afecta în nici un fel întregul program. Dacă transmiteți parametrii prin referință, atunci funcția poate schimba valorile parametrilor (variabilele) și aceasta va afecta programul principal. Deci, atunci când se folosește funcția local (), metoda de trecere a parametrilor prin referință funcționează puțin diferit: funcțiile pot schimba valorile parametrilor (variabilelor) care le-au trecut, dar aceasta va afecta doar funcția "top" - cea în care ), - nu va afecta în nici un fel programul principal.

Utilizați lista ca parametru de funcții.

Acum, când am dat seama de domeniul variabilelor, să analizăm parametrii funcției de cealaltă parte. Așa cum am spus deja, toți parametrii funcției sunt transmise în aceeași matrice, dar ce se întâmplă dacă trebuie să treci un parametru scalar la funcție, iar al doilea parametru o matrice? Următorul exemplu arată ce se va întâmpla:

firstSub ((0 ... 10), "AAAA");
sub primulSub local (@array, $ firstVar) = @_;
tipăriți ("firstSub: array = @array \ n");
print ("firstSub: firstVar = $ firstVar \ n");
>

firstSub: array = 0 1 2 3 4 5 6 7 8 9 10 AAAA
Utilizarea valorii neinitializate la linia test.pl 8.
firstSub: firstVar =

Vedeți că atunci când inițializați variabilele, matricea @array absoarbe toate elementele matricei parametrilor @, lăsând nimic pentru variabila $ firstVar. Acest lucru este confirmat de un mesaj de avertizare al interpretului Perl. Puteți rezolva această problemă prin schimbarea parametrilor - dacă puneți mai întâi o variabilă scalară și apoi o matrice, atunci totul va fi așa cum ar trebui:

firstSub ("AAAA", (0-10));
sub primeSub locale ($ firstVar, @array) = @_;
tipăriți ("firstSub: array = @array \ n");
print ("firstSub: firstVar = $ firstVar \ n");
>

firstSub: array = 0 1 2 3 4 5 6 7 8 9 10
firstSub: firstVar = AAAA

Puteți trece cât mai multe valori scalare pe care le doriți, dar numai o singură matrice. Dacă încercați să treceți mai multe tablouri la o funcție, elementele lor se îmbină pur și simplu într-o singură matrice și funcția nu va fi capabilă să afle - unde se termină o matrice și începe un altul.

Funcțiile nestauite (recursive).

Funcțiile se pot numi pe ele însele, care se încadrează în mai multe niveluri. În ce măsură aceasta depinde de implementarea specifică a Perl, de hardware-ul specific și de configurație. De obicei, aveți resurse suficiente pentru mașina dvs. și nu trebuie să vă faceți griji. Dar dacă sunteți interesat, puteți încerca să rulați acest program:

firstSub ();
sub primeSub print ("$ count \ n");
$ count ++;
firstSub ();
>

Eroare: excepție Runtime

Înainte de a imprima acest mesaj de eroare, programul va crește valoarea numărului $ până când este posibil un apel funcțional recursiv. Astfel, prin valoarea numărului $ puteți afla câte niveluri de apeluri recursive permite sistemul dvs.

Dar nu vă duceți în urma recursului - acest lucru ar trebui să fie tratat îndeaproape în cazuri speciale, de exemplu, cu unele calcule matematice.

Este posibil să aveți nevoie să utilizați o funcție cu un domeniu de aplicare limitat. Cum să aranjăm acest lucru cu variabilele, deja ne-am dat seama. Iată cum funcționează în cazul funcțiilor:

$ temp = performCalc (10, 10);
tipăriți ("temp = $ temp \ n");
sub performCalc meu ($ firstVar, $ secondVar) = @_;
suma mea $ square = sub return ($ _ [0] ** 2);
>;
întoarcere ($ square ($ firstVar) + $ pătrat ($ secondVar));
>;

După cum puteți vedea, avem o funcție $ square. Mai exact, $ square este o variabilă scalară obișnuită care se referă la o funcție. Pentru a accesa funcția, vom folosi semnul Înainte de numele variabilei $ square. Această funcție poate fi utilizată numai în cadrul funcției performCalc () - nu este disponibilă pentru restul programului.







Articole similare

Trimiteți-le prietenilor: