Aflarea despre aceste două concepte vă va ajuta să vă întăriți înțelegerea modului în care funcționează Rust și a modului în care puteți implementa funcțiile OOP.
Trăsăturile și durata de viață sunt componente cheie ale Rust. Puteți folosi trăsăturile pentru a defini comportamentele și capabilitățile pentru tipuri de implementat. Sunt foarte versatile, permițându-vă să scrieți cod mai generic, să reduceți duplicarea și să îmbunătățiți mentenabilitatea.
Rust folosește un alt mecanism – durata de viață – pentru a urmări proprietatea variabilelor în și în afara domeniului de aplicare. Acest lucru împiedică indicatorii suspendați în timpul dealocarii variabilelor.
Împreună, trăsăturile și durata de viață ajută la asigurarea siguranței tipului, a memoriei și a fiabilității codului.
Înțelegerea trăsăturilor în Rust
Trăsăturile sunt colecții de metode pe care alte tipuri le pot implementa. Trăsăturile sunt asemănătoare cu interfețe în limbi precum Java, Go și TypeScript, dar mai flexibile.
Veți folosi
trăsătură cuvânt cheie pentru a defini trăsăturile în Rust, urmat de o declarație a semnăturilor metodei.trăsăturăMyTrait {
fnmetoda_mea(&de sine);
}
Codul definește o trăsătură numită MyTrait cu metoda_mea metodă. The &de sine parametrul indică faptul că metoda se referă la obiectul tipului de implementare ca prim parametru.
După definirea unei trăsături, o puteți implementa pentru tipurile dvs. personalizate.
Iată cum puteți implementa o trăsătură pentru tipurile dvs. de structuri.
structPersoană {
Nume: Şir,
vârstă: u32,
}
impl Info pentru Persoana {
fnrezumat(&de sine) {
println!(„Numele meu este {} și am {} ani.”, de sine.Nume, de sine.vârstă);
}
}
The Persoană instrumente de struct Info, și puteți suna la rezumat metoda pe cazuri de Persoană struct.
fnprincipal(){
lăsa john = Persoană { nume: Şir::din("Ioan"), vârsta: 30 };
john.rezumat(); // Ieșire: Numele meu este John și am 30 de ani.
}
The Ioan variabila este o instanță a Persoană struct.
The principal apeluri de funcții rezumat care imprimă un mesaj pe consolă:
Enumerările pot implementa trăsături. Iată cum puteți defini o enumerare cu variante care implementează rezumat metodă:
enumerareMyEnum {
VariantaA,
Varianta B,
}
impl Info pentru MyEnum {
fnrezumat(&de sine) {
Mecide sine {
MyEnum:: VariantA => {
// implementare pentru VariantA
}
MyEnum:: VariantB => {
// implementare pentru VariantB
}
}
}
}
Utilizarea trăsăturilor pentru parametrii funcției și valorile returnate
Puteți utiliza trăsături ca parametri de funcție și valori returnate. Utilizarea trăsăturilor ca parametri ai funcției este utilă pentru scrierea codului generic cu mai multe tipuri.
Iată o funcție care preia un parametru de orice tip pe care îl implementează Info.
fnFă ceva(valoare: T) {
valoare.rezumat();
}
The sintaxa specifică că T trebuie implementat Info. Puteți apela la rezumat funcţionează cu orice valoare care se implementează Info.
Vieți în Rust
Instrumentul de verificare a împrumuturilor de la Rust analizează programele și asigură utilizarea adecvată a memoriei. În rugină, fiecare valoare are un proprietar care este responsabil pentru dealocarea valorii. Când variabilele împrumută valori, ei împrumută o referință la valoarea transmisă, dar proprietarul își păstrează proprietatea.
Duratele de viață sunt o modalitate de a vă asigura că valorile împrumutate sunt utilizate corect. O durată de viață este o etichetă atașată unei referințe, care descrie cât de mult este valabilă referința.
În Rust, puteți specifica o durată de viață folosind o adnotare apostrofă:
func<'A>
La crearea unei referințe, referinței i se atribuie o durată de viață care descrie cât de mult este valabilă. Dacă aveți o funcție care preia referința la o valoare, durata de viață trebuie să fie mai lungă decât apelul funcției pentru a vă asigura că valoarea este validă atunci când funcția revine.
Iată un exemplu de specificație a duratei de viață într-o funcție.
fnFă ceva<'A>(x: &'Ai32) -> &'Ai32 {
X
}
fnprincipal() {
lăsa x = 42;
lăsa rezultat = face_ceva(&x);
println!("Rezultatul este: {}", rezultat);
}
În Fă ceva funcția, cea 'A parametrul de viață indică faptul că referința la X este valabil atâta timp cât apelul funcției. Referința returnată este, de asemenea, valabilă atâta timp cât apelul funcției.
The principal funcția imprimă rezultatul pasând o referință la X variabilă în principal funcția către consolă.
Sintaxa de viață poate fi verbosă, dar este esențială pentru siguranța și gestionarea memoriei. Regulile de eliziune de trei vieți oferă linii directoare care îi permit lui Rust să deducă durata de viață a referințelor în anumite situații.
Regula de viață a intrării
Regula de viață de intrare specifică că, dacă o funcție sau o metodă ia una sau mai multe referințe ca parametri de intrare, Rust presupune că toate referințele au aceeași durată de viață.
Mai simplu spus, durata de viață a referințelor de ieșire va fi aceeași cu cea a referințelor de intrare.
fncel mai lung<'A>(x: &'Astr, y: &'Astr) -> &'Astr {
dacă x.len() > y.len() { x } altfel {y}
}
În cel mai lung Funcție, Rust deduce că durata de viață a referinței de ieșire este aceeași cu cea de intrare, deoarece ambele au același parametru de viață 'A.
Regula de viață a intrării facilitează scrierea funcțiilor generice care iau mai multe referințe ca intrare.
Regula de viață a ieșirii
Regula de viață de ieșire specifică că, dacă o funcție sau o metodă returnează o referință, Rust va presupune că durata de viață a referinței de ieșire este diferită de durata de viață a oricărei referințe de intrare.
fnprimul cuvânt<'A>(e: &'Astr) -> &'Astr {
s.split_whitspace().next().unwrap()
}
În această funcție, Rust deduce că durata de viață a referinței de ieșire este diferită de durata de viață a referinței de intrare, deoarece split_whitspace() metoda creează o referință de ieșire care nu acceptă parametrii de referință de intrare.
Regulă Eliziunea vieților
Regula de eliziune a duratelor de viață se aplică dacă o funcție sau o metodă ia o referință sau un parametru de intrare și returnează o referință. În acest caz, Rust presupune că referința de ieșire are aceeași durată de viață ca referința de intrare.
fncel mai lung<'A>(x: &'Astr, y: &str) -> &'Astr {
dacă x.len() > y.len() { x } altfel {y}
}
În această funcție, Rust deduce că durata de viață a referinței de ieșire este aceeași cu durata de viață a referinței de intrare, deoarece referința de intrare y nu are parametru de viață. Rugina elidează parametrul de viață pentru y și presupune că are aceeași durată de viață ca X.
Această regulă face mai ușor să scrieți funcții care iau o referință de intrare și returnează o referință de ieșire.
Trăsături și durate de viață
Puteți combina trăsături și durate de viață pentru a crea funcții generice care funcționează pentru tipurile care implementează o trăsătură și au o durată de viață validă.
Iată o trăsătură și o funcție care se referă la o valoare care implementează trăsătura.
trăsăturăToString {
fnto_string(&de sine) -> Şir;
}
fnto_string<'A, T: ToString>(t: &'A T) -> Şir {
t.to_string()
}
Aici, parametrul de viață 'A asigură că referinţa t este valabil pe durata de viață a obiectului la care face referire. Puteți folosi to_string funcția cu tipuri care implementează ToString trăsătură având o viață valabilă.
Trăsăturile formează baza pentru implementarea conceptelor POO în Rust
Trăsăturile vă permit să definiți comportamentele. Deși Rust nu este un limbaj de programare orientat pe obiecte (OOP), puteți folosi trăsături pentru a implementa concepte OOP de la încapsulare la moștenire, polimorfism și abstracție.
Implementarea acestor concepte OOP cu trăsături face ca programele dvs. Rust să fie scalabile, robuste, întreținute și eficiente.