Att lära sig om dessa två koncept hjälper till att stärka din förståelse för hur Rust fungerar och hur du kan implementera OOP-funktioner.
Egenskaper och livslängder är nyckelkomponenter i Rust. Du kan använda egenskaper för att definiera beteenden och förmågor för typer att implementera. De är mycket mångsidiga, vilket gör att du kan skriva mer generisk kod, minska dubbelarbete och förbättra underhållsbarheten.
Rust använder en annan mekanism – livstider – för att spåra ägande av variabler inom och utanför räckvidden. Detta förhindrar hängande pekare under variabel deallokering.
Tillsammans bidrar egenskaper och livslängder till att säkerställa typsäkerhet, minnessäkerhet och kodtillförlitlighet.
Förstå egenskaper hos rost
Egenskaper är samlingar av metoder som andra typer kan implementera. Egenskaper liknar gränssnitt på språk som Java, Go och TypeScript men mer flexibla.
Du kommer att använda drag nyckelord för att definiera egenskaper i Rust, följt av en deklaration av metodsignaturer.
dragMyTrait {
fnmin_metod(&själv);
}
Koden definierar en egenskap som heter MyTrait med en min_metod metod. De &själv parameter indikerar att metoden refererar till objektet för implementeringstypen som dess första parameter.
Efter att ha definierat en egenskap kan du implementera den för dina anpassade typer.
Så här kan du implementera en egenskap för dina strukturtyper.
strukturPerson {
namn: Sträng,
ålder: u32,
}
impl Info för Person {
fnsammanfattning(&själv) {
println!("Jag heter {} och jag är {} år gammal.", själv.namn, själv.ålder);
}
}
De Person strukturera redskap Info, och du kan ringa till sammanfattning metod på instanser av Person struktur.
fnhuvud(){
låta john = Person { namn: Sträng::från("John"), ålder: 30 };
john.summary(); // Output: Jag heter John och är 30 år gammal.
}
De john variabel är en instans av Person struktur.
De huvud funktionsanrop sammanfattning som skriver ut ett meddelande till konsolen:
Enums kan implementera egenskaper. Så här kan du definiera en enum med varianter som implementerar sammanfattning metod:
uppräkningMyEnum {
VariantA,
VariantB,
}
impl Info för MyEnum {
fnsammanfattning(&själv) {
matchsjälv {
MyEnum:: VariantA => {
// implementering för VariantA
}
MyEnum:: VariantB => {
// implementering för VariantB
}
}
}
}
Använda egenskaper för funktionsparametrar och returvärden
Du kan använda egenskaper som funktionsparametrar och returvärden. Att använda egenskaper som funktionsparametrar är praktiskt för att skriva generisk kod med flera typer.
Här är en funktion som tar en parameter av vilken typ som helst som implementerar Info.
fngöra någonting(värde: T) {
value.summary();
}
De syntax anger det T måste genomföra Info. Du kan ringa till sammanfattning funktion med vilket värde som helst som implementerar Info.
Livstider i Rust
Rusts verktyg för lånekontroll analyserar program och säkerställer korrekt minnesanvändning. I Rust, varje värde har en ägare som är ansvarig för att deallokera värdet. När variabler låna värden, lånar de en referens till värdet som passerat, men ägaren behåller äganderätten.
Livslängder är ett sätt att säkerställa att lånade värden används korrekt. En livstid är en etikett som är fäst vid en referens, som beskriver hur länge referensen är giltig.
I Rust kan du ange en livstid med en apostrofkommentar:
func<'a>
När du skapar en referens tilldelas referensen en livslängd som beskriver hur länge den är giltig. Om du har en funktion som tar referensen till ett värde måste livslängden vara längre än funktionsanropet för att säkerställa att värdet är giltigt när funktionen kommer tillbaka.
Här är ett exempel på livstidsspecifikation i en funktion.
fngöra någonting<'a>(x: &'ai32) -> &'ai32 {
x
}
fnhuvud() {
låta x = 42;
låta resultat = gör_något(&x);
println!("Resultatet är: {}", resultat);
}
I den göra någonting funktion, den 'a lifetime parameter indikerar att referensen till x är giltig så länge funktionsanropet. Den returnerade referensen är också giltig så länge som funktionsanropet.
De huvud funktionen skriver ut resultatet genom att skicka en referens till x variabel i huvud funktion till konsolen.
Livstidssyntaxen kan vara utförlig, men den är viktig för säkerhet och minneshantering. Elisionsregler för tre livslängder ger riktlinjer som gör att Rust kan sluta sig till livslängden för referenser i vissa situationer.
Input Lifetime Regel
Ingångslivstidsregeln anger att om en funktion eller metod tar en eller flera referenser som indataparametrar, antar Rust att alla referenser har samma livslängd.
Enkelt uttryckt kommer livslängden för utgående referenser att vara densamma som för ingångsreferenserna.
fnlängst<'a>(x: &'astr, y: &'astr) -> &'astr {
om x.len() > y.len() { x } annan {y}
}
I den längst funktion, Rust drar slutsatsen att livslängden för utgångsreferensen är densamma som ingångsreferensen eftersom de båda har samma livstidsparameter 'a.
Livstidsregeln för indata gör det lätt att skriva generiska funktioner som tar flera referenser som indata.
Utgångslivstidsregeln
Utdatalivslängdsregeln anger att om en funktion eller metod returnerar en referens, kommer Rust att anta att livslängden för utdatareferensen skiljer sig från livstiden för någon ingångsreferens.
fnförsta ordet<'a>(s: &'astr) -> &'astr {
s.split_whitespace().next().unwrap()
}
I den här funktionen drar Rust slutsatsen att livslängden för utgångsreferensen skiljer sig från livslängden för ingångsreferensen eftersom split_whitespace() metoden skapar en utdatareferens som inte tar några indatareferensparametrar.
The Elision of Lifetimes Regel
Elision of lifetimes-regeln gäller om en funktion eller metod tar en referens eller indataparameter och returnerar en referens. I så fall antar Rust att utgångsreferensen har samma livslängd som ingångsreferensen.
fnlängst<'a>(x: &'astr, y: &str) -> &'astr {
om x.len() > y.len() { x } annan {y}
}
I den här funktionen drar Rust slutsatsen att livslängden för utgångsreferensen är densamma som livslängden för ingångsreferensen eftersom ingångsreferensen y har ingen livstidsparameter. Rost eliminerar livstidsparametern för y och antar att den har samma livslängd som x.
Denna regel gör det lättare att skriva funktioner som tar en ingångsreferens och returnerar en utdatareferens.
Egenskaper och livstider
Du kan kombinera egenskaper och livstider för att skapa generiska funktioner som fungerar för typer som implementerar en egenskap och har en giltig livslängd.
Här är en egenskap och en funktion som refererar till ett värde som implementerar egenskapen.
dragAtt stränga {
fnatt stränga(&själv) -> Sträng;
}
fnatt stränga<'a, T: Att stränga>(t: &'a T) -> Sträng {
t.to_string()
}
Här, livstidsparametern 'a säkerställer att referensen t är giltig under hela livslängden för objektet som det refererar till. Du kan använda att stränga funktion med typer som implementerar Att stränga egenskap som har en giltig livstid.
Egenskaper utgör grunden för implementering av OOP-koncept i rost
Egenskaper gör att du kan definiera beteenden. Även om Rust inte är ett objektorienterat programmeringsspråk (OOP), kan du använda egenskaper för att implementera OOP-koncept från inkapsling till arv, polymorfism och abstraktion.
Genom att implementera dessa OOP-koncept med egenskaper blir dina Rust-program skalbara, robusta, underhållbara och effektiva.