Înțelegerea variabilelor, a matricelor, a buclălor și a null Analogia notei post-it

Ce face var de fapt, și de ce nu stabilește myObject = null elimina de fapt obiectul? Aceste întrebări se leagă de un concept fundamental în codificare, relevant dacă limbajul ales este AS3, JavaScript sau C # și poate fi înțeles utilizând câteva elemente comune din dulapul de papetărie.


Ce este o variabilă?

Să începem cu elementele de bază. Să presupunem că vrei să păstrezi vârsta prietenului tău Bill:

 var ageOfBill: Număr = 24;

(Voi folosi AS3 pentru aceste exemple, dar conceptele de bază sunt aceleași în JavaScript și C #.

În JavaScript, sintaxa este aproape aceeași, dar nu specificăm că vârsta este un număr:

 var ageOfBill = 24;

În C # nu folosim var , dar specificăm tipul de variabilă:

 scurtă ageOfBill = 24;

Nu este suficient de diferit pentru a fi confuz, sper.)

Ce se întâmplă aici? Gândește-te în felul acesta:

  • var (sau mic de statura, în C #) înseamnă "primiți o notă post-it nouă".
  • ageOfBill înseamnă, scrie ageOfBill în partea de sus, în stilou ".
  • = 24 înseamnă, scrie 24 pe notă, în creion ".

Dacă mai târziu ne dăm seama că Bill este de fapt mai tânăr decât ne-am gândit?

 var ageOfBill = 24; // ... mai târziu ... ageOfBill = 20;

Asta înseamnă că găsim pe noi ageOfBill notă, ștergeți 24, si scrie 20 pe el în schimb.

Noi ar putea scrie var din nou:

 var ageOfBill: Număr = 24; // ... mai târziu ... var ageOfBill: Number = 20;

... dar acest cod nu este bun, pentru că var spune, "primiți o notă post-it nouă". Dacă faceți acest lucru, compilatorul va afla, de obicei, ce vreți să înțelegeți - adică că doriți să schimbați ceea ce este scris pe existent ageOfBill Post-it nota, mai degrabă decât de a obține unul unul proaspăt - dar probabil că se va plânge.

 Avertisment: # 3596: Definiție variabilă duplicat.

Depinde de limbă și de mediul dvs. de codificare.

Deci, putem cere compilatorului să obțină o notă post-it nouă și să scrie o etichetă pe ea, fără a scrie nimic pe creion? Poate că am putea face asta pentru prietenul lui Bill, Marty, a cărui vârstă nu știm:

 var ageOfMarty: Număr;

De fapt (cel puțin în AS3), aceasta va primi o notă post-it nouă, scrieți ageOfMarty în partea de sus, în stilou ... și apoi scrie o valoare inițială implicită de 0 pe acolo în creion:

Deci, cu alte cuvinte, nu putem avea o notă Post-it de genul asta, fără ca aceasta să aibă valoare.

Bine - ce-ar fi dacă vrem să păstrăm vârsta celui mai bun prieten al lui Bill, Ted, care știm că este de aceeași vârstă?

 var ageOfTed: Număr = ageOfBill;

Ce se întâmplă aici este, calculatorul se uită la ageOfBill Post-it, apoi copiază numărul scrise pe ea în creion într-un Post-it nou, pe care scrie ageOfTed în vârful stiloului.

Aceasta este doar o copie; dacă vom schimba apoi valoarea lui ageOfBill nu va afecta ageOfTed:

 ageOfBill = 21;

Asa de! Asta e destul de simplu și poate chiar intuitiv. Acum hai să vorbim despre primul punct comun de durere: matrice.


Ce este o matrice?

Gândiți-vă la o matrice ca liant inelar.

(Am vrut să spun un rolodex ...

... dar mi-am dat seama că nu am văzut nici măcar unul în viața reală.)

Fiecare foaie în interiorul liantului este ca una dintre acele note Post-it, cu excepția lipirii etichetei cu stilou în partea de sus. În schimb, se referă la fiecare foaie cu numele liantului și numărul paginii foii.

Să presupunem că avem o mulțime de prieteni, în nici o ordine particulară. Cine se află pe prima pagină (pagina # 0)?

 urme (prieteni [0]);

(urmă() scrie doar linia la ieșirea de depanare; în JavaScript, puteți utiliza console.log () și în C # s-ar putea folosi Console.WriteLine () pentru același scop.)

Este Bill!

Deci, acum, ce face următoarea linie?

 var firstFriend: String = prieteni [0];

Ea primește o notă post-it nouă (din cauza var cuvânt cheie), scrie firstFriend în partea de sus a stiloului, apoi copiază tot ce este scris pe prima pagină a liantului pe acea notă în creion.

(Tine minte, Şir înseamnă doar o bucată de text.)

Putem suprascrie ceea ce este scris pe orice pagină a liantului, la fel ca în notele Post-it:

 prieteni [0] = "Kyle";

... și, desigur, acest lucru nu afectează firstFriend Postează.

Legătura este o analogie aptă, deoarece - ca și în cazul unei matrice - luați paginile afară, adăugați altele noi și rearanjați-le. Dar amintiți-vă că paginile individuale se comportă exact ca notele Post-it, cu excepția faptului că nu au propriile etichete de stilou, doar numere de pagină.

Încă destul de simplu, sper. Deci, aici este o întrebare interesantă: ce se întâmplă atunci când faceți următoarele?

 var listOfNames: Array = prieteni;

Uh ...


Nu poți scrie asta pe o postare

Am înșelat un pic aici, pentru că am vorbit despre aglomerări, fără a explica vreodată cum îl creăm pe primul loc. Deci, să abordăm asta acum.

Să presupunem că tastați:

 var prieteni: Array = ["Bill", "Marty", "Ted"];

… Ce se întâmplă?

Ei bine, ca de obicei, prieteni var înseamnă că primim o notă post-it nouă și scriem prieteni în partea de sus, în stilou:

Dar ce scriem pe el în creion?

Este o întrebare de tip truc: nu scriem orice.

Vedea, mulțime înseamnă "primiți un nou inel de legătură". Și ["Bill", "Marty", "Ted"] înseamnă "puneți trei pagini în liant, cu aceste nume pe acesta":


Nu puteți vedea paginile "Marty" și "Ted", dar ele sunt în totalitate acolo.

Și apoi? E simplu! Îl lipim prieteni Notă post-it la coperta de liant:

Acum, când scriem:

 urme (prieteni [0]);

... știm că trebuie să găsim eticheta Post-it prieteni, apoi uita-te la ceea ce este scris pe prima pagină (pagina # 0) a liantului căruia i sa blocat.

Există de fapt foarte puține tipuri de variabile în care o valoare este scrisă pe o notă Post-it în creion. În AS3, singurele astfel de tipuri (numite "primitive") sunt:

  • Număr
  • Şir
  • int
  • uint
  • boolean

Pentru orice altceva - Obiect, MovieClip, XML, și așa mai departe - lipim nota Post-it pe elementul în sine.

(Detaliile sunt puțin diferite în JavaScript și C #, dar, în general, se aplică aceeași idee.)

Deci, să ne întoarcem la întrebarea noastră anterioară. Când tastăm:

 var listOfNames: Array = prieteni;

… ce se întâmplă?

Din nou, știm asta var listOfNames înseamnă "primiți o notă post-it nouă și scrieți-o listOfNames în partea de sus a stiloului. "Și acum știm asta mulțime înseamnă că vom lipi nota Post-it la ceva (un liant), mai degrabă decât să scriem ceva pe Post-it în creion.

Anterior, când am făcut ceva similar, am copiat conținutul unei note post-it pe alta. Deci, aici, ar trebui să luăm un nou liant și să copiem toate paginile din prieteni liant în el?

De fapt nu! Tot ce facem este să înmânați acest lucru nou listOfNames Notați-l pe același liant ca și prieteni Notiță.

Acum, prieteni și listOfNames fiecare se referă la exact aceeași matrice. Deci, dacă scriem:

 listOfNames [0] = "Emmett";

… atunci prieteni [0] voi de asemenea fi Emmett, deoarece listOfNames [0] și prieteni [0] consultați exact aceeași pagină în exact același liant! Și pentru că pagina conține numai un String (care este un tip "primitiv"), atunci am șters doar ceea ce a fost scris pe acea pagină anterior și scris Emmett acolo în loc.


Deci, ce face nul Însemna?

Văzut așa, nul este destul de ușor de înțeles. Aceasta afirmatie:

 prieteni = null;

... înseamnă doar, "eliminați prieteni Post-it nota din orice este în prezent blocat la ".

prieteni Post-it încă există, doar nu este blocat de nimic. Deci, dacă tastați:

 urme (prieteni [0]);

sau

 prieteni [0] = "Henry";

... atunci veți avea o eroare, pentru că încercați să faceți referire la prima pagină a liantului că prieteni Post-ul este blocat - dar nu este blocat de nimic!

Deci, pentru a fi clar, setarea prieteni = null nu afectează deloc liantul. Încă puteți să-l accesați prin intermediul telefonului listOfNames. Și puteți chiar tasta:

 friends = listOfNames;

... să mergem înapoi la situația veche:


Colecția de gunoi

Cum am spus, setarea prieteni = null nu afectează direct liantul, dar poate avea un indirect efect.

Dacă nu există note post-it lipite la liant, atunci nu există nicio cale pentru ca oricine să acceseze liantul vreodată din nou. Pur și simplu se va afla în jur, complet inaccesibil. Dar având toate aceste lianți (și alte obiecte) situate în jurul lor, complet abandonate, este o adevărată risipă de spațiu - ei aglomerează memoria calculatorului.

Aici este locul colector de gunoi intră. Acesta este un instrument care verifică periodic orice obiecte "pierdute" și le aruncă în coșul de gunoi - și odată ce au plecat, au plecat definitiv; dacă este colectată o matrice, atunci toate paginile sunt, de asemenea.

În majoritatea scopurilor practice, acest lucru nu vă afectează deloc; obiectele primesc numai gunoi colectat dacă sunt pierduți și nu pot fi găsiți prin codul dvs. Dacă aveți multe dintre acestea situate în jur, atunci este posibil să observați o ușoară întârziere în fiecare moment în care colectorul de gunoi își face treaba (este nevoie de puțin timp pentru a colecta în mod activ gunoiul). Beneficiul este că acest lucru elimină mai mult spațiu (memorie) pentru aplicația dvs..

(Dacă doriți să aflați mai multe despre acest subiect, citiți articolele lui Daniel Sidhion privind colectarea gunoiului și punerea în comun a obiectelor.)


Arrays of Objects

Bine, există un concept mai mare pentru a înțelege - și este cel mai complex încă.

Luați în considerare acest fragment:

 var primaFriendDetails: Array = ["Bill", 20]; var secondFriendDetails: Array = ["Marty", 16]; var thirdFriendDetails: Array = ["Ted", 20]; var allPriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];

Ce naiba face acea muncă?

Să începem cu ceea ce știm. Primele trei linii sunt ușor; pentru fiecare dintre noi:

  • Luați un liant proaspăt.
  • Inserați o pagină cu numele prietenului scris pe creion.
  • Pentru a insera o altă pagină cu vârsta prietenului scrise pe ea în creion.
  • Obțineți un Post-it proaspăt și scrieți eticheta potrivită în partea de sus a stiloului injector (pen-ului).
  • Puneți Post-it pe liant.

În ceea ce privește această linie:

 var allPriends: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails];

... vom avea nevoie de niște șir și de o bandă.

Ne putem gândi la acea linie ca fiind echivalentă cu acest fragment:

 var allPriends: Array = []; toți prietenii [0] = firstFriendDetails; toți prietenii [1] = secondFriendDetails; toți prietenii [2] = thirdFriendDetails;

Prima linie este ușoară: obțineți un liant proaspăt și o notă post-it nouă, scrieți toți prietenii pe nota Post-it și lipiți-o la liant.

În ceea ce privește al doilea rând:

 toți prietenii [0] = firstFriendDetails;

Amintiți-vă că am spus că fiecare pagină dintr-un liant este ca o notă Post-it, cu excepția a ceea ce nu este scris în stilou. Dacă prima pagină a fost Post-it, atunci l-am fi lipit doar în partea din față a casei firstFriendDetails liant, drept?

... dar nu poate fi atât pe partea din față a liantului și în interiorul celuilalt liant. Deci, în schimb, folosim șirul:

Același lucru pentru ceilalți doi:

Atunci când vrem să știm ce Allfriends [2] se referă la, noi doar deschideți toți prietenii liant la acea pagină și urmați șirul - care, desigur, duce la thirdFriendDetails liant.

În mod similar, pentru Allfriends [1] [0], ne dăm seama mai întâi ce liant Allfriends [1] se referă la, și apoi ne uităm la prima pagină din acea liant ... deci Allfriends [1] [0] este Marty!


buclele

Acum puneți toate aceste informații împreună și țineți minte la citirea acestui fragment:

 prieteni var: Array = ["Bill", "Marty", "Ted", "Emmett", "Henry"]; var curentIndex: int = 0; var currentFriend: String; în timp ce (currentIndex < 5)  currentFriend = friends[currentIndex]; trace(currentFriend);  var lastFriend:String = currentFriend; trace(lastFriend);

Dacă modificăm valoarea currentFriend în interiorul bucla?

 prieteni var: Array = ["Bill", "Marty", "Ted", "Emmett", "Henry"]; var curentIndex: int = 0; var currentFriend: String; în timp ce (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend = "Herbert"; trace(currentFriend);  trace(friends[0]);

Ce se întâmplă dacă matricea conține obiecte non-primitive (MovieClips, imagini, tablouri, obiecte 3D, orice)?

 var prieteni: Array = [primul prieten, al doilea prieten, al treilea prieten, al patrulea prieten, al cincilea prieten]; var curentIndex: int = 0; var currentFriend: MovieClip; // sau ": Image" sau ": Object" sau ": Array" sau oricare ar fi în timp ce (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend = sixthFriend;  //What is the value of friends[0] now?

În cele din urmă, ceea ce ar fi dacă matricea conține alte matrice, care conțin ele însele primitive?

 var primaFriendDetails: Array = ["Bill", 20]; var secondFriendDetails: Array = ["Marty", 16]; var thirdFriendDetails: Array = ["Ted", 20]; var fourthPriendDetails: Array = ["Emmett", 50]; var fifthPriendDetails: Array = ["Henry", 36]; var prieteni: Array = [firstFriendDetails, secondFriendDetails, thirdFriendDetails, fourthFriendDetails, fifthFriendDetails]; var curentIndex: int = 0; var currentFriend: Array; în timp ce (currentIndex < 5)  currentFriend = friends[currentIndex]; currentFriend[0] = "John"; currentFriend = ["Herbert", 29]; 

Ce credeți că valoarea lui prieteni [3] [0] va fi după aceea?


Alte biți și piese

Iată câteva alte note importante pe care trebuie să le cunoașteți:

Obiecte

În AS3 și JavaScript, obiectele sunt asemănătoare unei arhitecturi, cu excepția fiecărei pagini la care se face referire mai degrabă de o etichetă decât de numărul paginii. Deci puteți tasta:

 var detaliiOfBill: Object = ; // "" înseamnă "a crea un obiect" detailsOfBill.title = "Esquire"; detailsOfBill.bandName = "Wyld Stallyns"; detailsOfBill.allNames = ["Bill", "S.", "Preston"];

… și asta este cam cum ar fi obținerea unui liant proaspăt, lipirea unui detailsOfBill Post-it pe partea din față, și umple-l cu trei pagini. Prima pagină are eticheta titlu scrise deasupra în stilou și cuvânt nobil scrise pe ea în creion; a doua pagină are eticheta bandName în pix și Wyld Stallyns în creion. A treia pagină are eticheta allNames dar nu are nimic scris pe el în creion; în schimb, un șir îi atașează altui liant obișnuit, ale cărui pagini nu sunt etichetate: se menționează prima pagină Factură, a doua spune S., iar al treilea spune Preston, toți în creion.

(Pentru a face lucrurile și mai confuze, matricele sunt din punct de vedere tehnic o formă specială a obiectului și dacă credeți că e rău, funcțiile pot fi văzute și ca un tip de Obiect, dar acesta este un subiect pentru un articol viitor ...)

Mai multe despre colecția de gunoi

Am spus că obiectele sunt colectate în cazul în care nu au nici o notă post-it blocată de ei, dar aceasta este o simplificare. Dacă o pagină a unui liant indică un obiect prin șir (adică dacă myArray [0] = myObject sau similar), atunci obiectul nu va fi colectat de gunoi. Același lucru se întâmplă dacă o pagină a unui liant indică un alt liant (array), sau dacă pagina unui liant obiect indică un liant al unui obiect ... și așa mai departe. Se aplică chiar dacă singura modalitate de accesare a obiectului este printr-un Post-it blocat la un liant care are o pagină legată de un alt liant, cu cât mai multe straturi adânci pe care doriți să-l faceți.

Practic, colectorul de gunoi colectează numai un element dacă nu poate fi atins prin orice altă variabilă.

Acest lucru explică de ce obiectele care sunt pe ecran, de obicei, nu pot fi colectate. În AS3, dacă în lista de afișare este un MovieClip sau alt tip de DisplayObject, acesta este adăugat automat la ceea ce este în esență o matrice ascunsă de obiecte de afișare (pe care le puteți accesa prin getChildAt ()). Structuri similare există în JavaScript și C #. Deci, dacă pe ecran este un grafic și eliminați toate referințele la acesta din variabile, arrayuri și obiecte, acesta nu va fi colectat până când nu îl eliminați din lista de afișare.


Alte intrebari?

Sper că acest lucru ajută la clarificarea lucrurilor. Este cu siguranță un concept confuz atunci când o întâlniți pentru prima dată: unele variabile conțin de fapt a valoare, în timp ce alții conțin doar referinţă la un obiect. Nu vă faceți griji dacă nu sunteți sigur 100% exact ce se întâmplă; se va face mult mai multă sens după un pic de practică (și câteva greșeli!).

Cu toate acestea, dacă aveți întrebări specifice despre acest lucru, trebuie doar să lipiți un comentariu mai jos și voi face tot posibilul pentru a răspunde.

Vă mulțumim pentru lectură!

Cod