ca mulți dezvoltatori, sunt interesat de Rust de ceva timp. Nu numai pentru că apare în atât de multe titluri de pe Hacker News, sau din cauza abordării noi limba ia la siguranță și performanță, dar, de asemenea, pentru că oamenii par să vorbească despre asta cu un sentiment special de dragoste și admirație. În plus, Rust este de interes deosebit pentru mine, deoarece împărtășește unele dintre aceleași obiective și caracteristici ale limbajului meu preferat: Swift. Din moment ce am luat recent timp pentru a face încerca Rust în unele proiecte personale mici, am vrut să ia un pic de timp pentru a documenta impresiile mele de limba, mai ales în modul în care se compară cu Swift.

imaginea de ansamblu

Rust și Swift au o mulțime de lucruri în comun: ambele sunt limbi compilate cu sisteme de tip puternic, modern și un accent pe siguranță. Caracteristici precum tipurile algebrice și manipularea de primă clasă a valorilor opționale ajută la mutarea multor clase de erori de la timpul de rulare la timpul de compilare în ambele limbi.

deci, cum diferă aceste limbi? Cel mai bun mod în care pot caracteriza diferența este:

Swift îl face ușor de a scrie cod în condiții de siguranță.
rugina face dificilă scrierea codului nesigur.

aceste două afirmații ar putea suna echivalent, dar există o distincție importantă. Ambele limbi au instrumente pentru a obține siguranța, dar fac compromisuri diferite pentru a o atinge: Swift acordă prioritate ergonomiei în detrimentul performanței, în timp ce Rust acordă prioritate performanței în detrimentul ergonomiei.

Compromisul: Performanță vs ergonomie

cel mai mare MOD în care această diferență de prioritate este demonstrată este abordarea pe care aceste limbi o au pentru gestionarea memoriei. Voi începe cu Rust, deoarece abordarea limbajului în gestionarea memoriei este unul dintre punctele sale unice de vânzare.

în Rust, memoria este gestionată în primul rând static (Da, există și alte moduri de gestionare a memoriei, cum ar fi numărarea referințelor, dar le vom ignora deocamdată). Ce înseamnă acest lucru este că compilatorul Rust analizează programul dvs. și, conform unui set de reguli, decide când memoria ar trebui alocată și eliberată.

pentru a oferi siguranță, Rust folosește o nouă strategie numită verificarea împrumuturilor. Modul în care funcționează în practică este că, în calitate de programator, de fiecare dată când treceți în jurul unei variabile (adică o referință la o locație de memorie), trebuie să specificați dacă referința este mutabilă sau imuabilă. Compilatorul folosește apoi un set de reguli pentru a vă asigura că nu puteți muta o singură bucată de memorie în două locuri simultan, făcând astfel demonstrabil că programul dvs. nu are curse de date.

această abordare are câteva proprietăți foarte benefice în ceea ce privește utilizarea și performanța memoriei. Verificarea împrumuturilor poate fi foarte parsimonioasă cu memoria, deoarece în general evită copierea valorilor. De asemenea, evită performanța generală a unei soluții precum colectarea gunoiului, deoarece lucrarea se face în timpul compilării, mai degrabă decât în timpul rulării.

cu toate acestea, vine cu unele dezavantaje în ceea ce privește ușurința de utilizare. Datorită naturii proprietății în Rust, există unele modele de design care pur și simplu nu funcționează în Rust. De exemplu, nu este banal să implementați ceva de genul unei liste dublu legate sau a unei variabile globale. Acest lucru devine probabil mai intuitiv cu timpul și există soluții pentru aceste probleme, dar Rust impune cu siguranță limitări programatorului care nu sunt prezente în alte limbi.

deși nu se vorbește atât de des despre Rust, Swift are și o poveste interesantă atunci când vine vorba de gestionarea memoriei.

Swift are două tipuri fundamentale de variabile: tipuri de referință și tipuri de valori. În general, tipurile de referință sunt alocate heap și sunt gestionate prin numărarea referințelor. Aceasta înseamnă că, în timpul rulării, numărul de referințe la un obiect numărat de referință este urmărit, iar obiectul este nealocat atunci când numărul ajunge la zero. Numărarea referințelor în Swift este întotdeauna atomică: aceasta înseamnă că de fiecare dată când se schimbă un număr de referință, trebuie să existe o sincronizare între toate firele procesorului. Acest lucru are avantajul de a elimina posibilitatea ca o referință să fie eliberată în mod eronat într-o aplicație multi-threaded, dar are un cost semnificativ de performanță, deoarece sincronizarea procesorului este foarte costisitoare.

Rust are, de asemenea, instrumente pentru numărarea referințelor și numărarea referințelor atomice, dar acestea sunt opt-in, mai degrabă decât să fie implicit.

tipurile de valori, prin contrast, sunt alocate stivei în general, iar memoria lor este gestionată static. Cu toate acestea, comportamentul tipurilor de valori în Swift este mult diferit de modul în care Rust gestionează memoria. În Swift, tipuri de valori au ceea ce se numește „copy-on-write” comportament sunt copiate în mod implicit, ceea ce înseamnă de fiecare dată când un tip de valoare este scris la o nouă variabilă, sau a trecut la o funcție, se face o copie.

Copierea la scriere în mod implicit atinge unele dintre aceleași obiective ale verificării împrumutului: ca programator, în general, nu trebuie să vă faceți griji cu privire la o valoare care se schimbă misterios din cauza unor efecte secundare neașteptate în altă parte a programului. De asemenea, necesită o sarcină cognitivă puțin mai mică decât verificarea împrumuturilor, deoarece există clase întregi de erori de compilare legate de proprietate în Rust, care pur și simplu nu există în Swift. Cu toate acestea, vine la un cost: aceste copii suplimentare necesită utilizarea memoriei suplimentare și cicluri CPU pentru a finaliza.

în Rust este posibilă și copierea valorilor ca o modalitate de a reduce la tăcere erorile de verificare a împrumuturilor, dar acest lucru adaugă zgomot vizual, deoarece copiile trebuie specificate în mod explicit.

deci, aici avem un bun exemplu al compromisurilor făcute de aceste două limbi: Swift vă oferă câteva ipoteze generale despre modul în care memoria ar trebui gestionată, menținând în același timp un nivel de siguranță. Este un pic ca modul în care un programator C++ ar putea gestiona memoria în conformitate cu cele mai bune practici înainte de a se gândi mult la optimizare. Acest lucru face foarte ușor să sari și să scrii cod fără să te gândești prea mult la detalii de nivel scăzut și, de asemenea, să obții unele garanții de siguranță și corectitudine de bază pe care nu le-ai obține într-o limbă precum Python sau chiar Golang. Cu toate acestea, vine cu unele stânci de performanță, care este ușor să cadă fără să-și dea seama chiar până când executați programul. Este posibil să scrieți cod Swift de înaltă performanță, dar acest lucru necesită adesea profilare atentă și optimizare pentru a realiza.

Rust, pe de altă parte, vă oferă o mulțime de instrumente specifice pentru specificarea modului în care ar trebui gestionată memoria și apoi plasează unele restricții dure asupra modului în care le utilizați pentru a evita un comportament nesigur. Acest lucru vă oferă caracteristici de performanță foarte frumoase chiar din cutie, dar necesită să vă asumați cheltuielile cognitive suplimentare pentru a vă asigura că toate regulile sunt respectate.

concluzia mea a fost că, deși aceste limbi au unele obiective comune, ele au caracteristici fundamental diferite, care se pretează la diferite cazuri de utilizare. Rust, de exemplu, pare alegerea clară pentru ceva de genul dezvoltării încorporate, unde utilizarea optimă a ciclurilor de memorie și CPU este extrem de importantă și unde bucla de cod-compilare-rulare poate fi mai lentă, deci este valoros să prindeți orice problemă posibilă la momentul compilării. În timp ce Swift ar putea fi o alegere mai bună pentru ceva precum știința datelor sau logica fără server, unde performanța este o preocupare secundară și este valoros să lucrezi mai aproape de domeniul problemei fără a fi nevoie să iei în considerare o mulțime de detalii de nivel scăzut.

în orice caz, voi fi foarte interesat să urmez ambele limbi în viitor și voi urmări acest post cu mai multe observații despre comparația dintre Swift și Rust.

Lasă un răspuns

Adresa ta de email nu va fi publicată.