Das Kennenlernen dieser beiden Konzepte wird Ihnen helfen, Ihr Verständnis dafür zu vertiefen, wie Rust funktioniert und wie Sie OOP-Funktionen implementieren können.

Eigenschaften und Lebensdauern sind Schlüsselkomponenten von Rust. Sie können Eigenschaften verwenden, um Verhaltensweisen und Fähigkeiten für zu implementierende Typen zu definieren. Sie sind sehr vielseitig und ermöglichen es Ihnen, allgemeineren Code zu schreiben, Duplikate zu reduzieren und die Wartbarkeit zu verbessern.

Rust verwendet einen anderen Mechanismus – Lebenszeiten – um den Besitz von Variablen innerhalb und außerhalb des Geltungsbereichs zu verfolgen. Dies verhindert hängende Zeiger während der Freigabe von Variablen.

Gemeinsam tragen Eigenschaften und Lebensdauern dazu bei, Typsicherheit, Speichersicherheit und Codezuverlässigkeit zu gewährleisten.

Eigenschaften in Rust verstehen

Traits sind Sammlungen von Methoden, die andere Typen implementieren können. Eigenschaften sind ähnlich wie Schnittstellen in Sprachen wie Java, Go und TypeScript, aber flexibler.

instagram viewer

Sie verwenden die Merkmal Schlüsselwort, um Traits in Rust zu definieren, gefolgt von einer Deklaration von Methodensignaturen.

MerkmalMein Merkmal {
fnmeine_methode(&selbst);
}

Der Code definiert eine Eigenschaft namens Mein Merkmal mit einem meine_methode Methode. Der &selbst Parameter gibt an, dass die Methode als ersten Parameter auf das Objekt des implementierenden Typs verweist.

Nachdem Sie ein Merkmal definiert haben, können Sie es für Ihre benutzerdefinierten Typen implementieren.

So können Sie eine Eigenschaft für Ihre Strukturtypen implementieren.

StrukturPerson {
Name: Schnur,
Alter: u32,
}

impl Die Info für Person {
fnZusammenfassung(&selbst) {
drucken!("Mein Name ist {} und ich bin {} Jahre alt.", selbst.Name, selbst.Alter);
}
}

Der Person struct implementiert Die Info, und Sie können die anrufen Zusammenfassung Methode auf Instanzen der Person Struktur.

fnhauptsächlich(){
lassen john = Person {Name: Schnur::aus("John"), Alter: 30 };
john.summary(); // Ausgabe: Mein Name ist John und ich bin 30 Jahre alt.
}

Der John Variable ist eine Instanz von Person Struktur.

Der hauptsächlich Funktionsaufrufe Zusammenfassung die eine Nachricht an die Konsole ausgibt:

Enums können Eigenschaften implementieren. So können Sie eine Aufzählung mit Varianten definieren, die die implementieren Zusammenfassung Methode:

AufzählungMeineEnum {
VarianteA,
VarianteB,
}

impl Die Info für MyEnum {
fnZusammenfassung(&selbst) {
passenselbst {
MyEnum:: VariantA => {
// Implementierung für VariantA
}
MyEnum:: VariantB => {
// Implementierung für VariantB
}
}
}
}

Traits für Funktionsparameter und Rückgabewerte verwenden

Sie können Merkmale als Funktionsparameter und Rückgabewerte verwenden. Die Verwendung von Merkmalen als Funktionsparameter ist praktisch, um generischen Code mit mehreren Typen zu schreiben.

Hier ist eine Funktion, die einen Parameter eines beliebigen Typs akzeptiert, der implementiert wird Die Info.

fnetwas tun(Wert: T) {
value.summary();
}

Der Syntax gibt das an T umsetzen muss Die Info. Sie können die anrufen Zusammenfassung Funktion mit jedem Wert, der implementiert Die Info.

Leben in Rust

Das Borrow-Checker-Tool von Rust analysiert Programme und stellt die ordnungsgemäße Speichernutzung sicher. In Rost, Jeder Wert hat einen Besitzer das ist für die Freigabe des Werts verantwortlich. Wenn Variablen Werte ausleihen, leihen sie sich einen Verweis auf den übergebenen Wert aus, aber der Eigentümer behält das Eigentum.

Lebensdauern sind eine Möglichkeit sicherzustellen, dass geliehene Werte korrekt verwendet werden. Eine Lebensdauer ist ein Etikett, das an einer Referenz angebracht ist und beschreibt, wie lange die Referenz gültig ist.

In Rust können Sie eine Lebensdauer mit einer Apostroph-Annotation angeben:

Funktion<'A>

Beim Erstellen einer Referenz wird der Referenz eine Lebensdauer zugewiesen, die beschreibt, wie lange sie gültig ist. Wenn Sie eine Funktion haben, die den Verweis auf einen Wert übernimmt, muss die Lebensdauer länger sein als der Funktionsaufruf, um sicherzustellen, dass der Wert gültig ist, wenn die Funktion zurückkehrt.

Hier ist ein Beispiel für die Angabe der Lebensdauer in einer Funktion.

fnetwas tun<'A>(x: &'Ai32) -> &'Ai32 {
X
}

fnhauptsächlich() {
lassen x= 42;
lassen result = do_something(&x);
drucken!("Das Ergebnis ist: {}", Ergebnis);
}

Im etwas tun Funktion, die 'A Der Lebensdauerparameter gibt an, dass der Verweis auf X ist solange gültig wie der Funktionsaufruf. Die zurückgegebene Referenz ist auch gültig, solange der Funktionsaufruf.

Der hauptsächlich Die Funktion gibt das Ergebnis aus, indem sie einen Verweis auf die übergibt X Variable in der hauptsächlich Funktion zur Konsole.

Die Syntax für die Lebensdauer kann ausführlich sein, ist aber für die Sicherheit und die Speicherverwaltung unerlässlich. Drei-Lebensdauer-Eliminierungsregeln bieten Richtlinien, die es Rust ermöglichen, in bestimmten Situationen auf die Lebensdauer von Referenzen zu schließen.

Die Input-Lifetime-Regel

Die Eingabelebensdauerregel legt fest, dass Rust davon ausgeht, dass alle Referenzen dieselbe Lebensdauer haben, wenn eine Funktion oder Methode eine oder mehrere Referenzen als Eingabeparameter verwendet.

Einfach ausgedrückt, die Lebensdauer der Ausgangsreferenzen ist dieselbe wie die der Eingangsreferenzen.

fnam längsten<'A>(x: &'AStr, y: &'AStr) -> &'AStr {
Wenn x.länge() > y.länge() { x } anders {j}
}

Im am längsten Funktion, folgert Rust, dass die Lebensdauer der Ausgangsreferenz dieselbe ist wie die der Eingangsreferenz, da beide denselben Lebensdauerparameter haben 'A.

Die Eingabelebensdauerregel erleichtert das Schreiben generischer Funktionen, die mehrere Referenzen als Eingabe verwenden.

Die Output-Lifetime-Regel

Die Ausgabelebensdauerregel legt fest, dass Rust davon ausgeht, dass sich die Lebensdauer der Ausgabereferenz von der Lebensdauer jeder Eingabereferenz unterscheidet, wenn eine Funktion oder Methode eine Referenz zurückgibt.

fnerstes Wort<'A>(s: &'AStr) -> &'AStr {
s.split_whitespace().next().unwrap()
}

In dieser Funktion leitet Rust ab, dass sich die Lebensdauer der Ausgabereferenz von der Lebensdauer der Eingabereferenz unterscheidet, weil die split_whitespace() -Methode erstellt eine Ausgabereferenz, die keine Eingabereferenzparameter akzeptiert.

Die Elision of Lifetimes-Regel

Die Elision-of-Lifetimes-Regel gilt, wenn eine Funktion oder Methode eine Referenz oder einen Eingabeparameter übernimmt und eine Referenz zurückgibt. In diesem Fall geht Rust davon aus, dass die Ausgangsreferenz die gleiche Lebensdauer wie die Eingangsreferenz hat.

fnam längsten<'A>(x: &'AStr, y: &Str) -> &'AStr {
Wenn x.länge() > y.länge() { x } anders {j}
}

In dieser Funktion folgert Rust, dass die Lebensdauer der Ausgangsreferenz die gleiche ist wie die Lebensdauer der Eingangsreferenz, weil die Eingangsreferenz j hat keinen Lebensdauerparameter. Rust eliminiert den Lebensdauerparameter für j und geht davon aus, dass es die gleiche Lebensdauer hat wie X.

Diese Regel erleichtert das Schreiben von Funktionen, die eine Eingabereferenz annehmen und eine Ausgabereferenz zurückgeben.

Eigenschaften und Lebensdauer

Sie können Eigenschaften und Lebensdauern kombinieren, um generische Funktionen zu erstellen, die für Typen funktionieren, die eine Eigenschaft implementieren und eine gültige Lebensdauer haben.

Hier ist eine Eigenschaft und eine Funktion, die auf einen Wert verweist, der die Eigenschaft implementiert.

MerkmalToString {
fnto_string(&selbst) -> Schnur;
}

fnto_string<'A, T: ToString>(t: &'A T) -> Schnur {
t.to_string()
}

Hier der Lebensdauerparameter 'A sorgt dafür, dass die Referenz T ist für die Lebensdauer des Objekts gültig, auf das es verweist. Du kannst den... benutzen to_string Funktion mit Typen, die die implementieren ToString Eigenschaft mit einer gültigen Lebensdauer.

Traits bilden die Grundlage für die Implementierung von OOP-Konzepten in Rust

Merkmale ermöglichen es Ihnen, Verhaltensweisen zu definieren. Obwohl Rust keine objektorientierte Programmiersprache (OOP) ist, können Sie Traits verwenden, um OOP-Konzepte von Kapselung bis Vererbung, Polymorphismus und Abstraktion zu implementieren.

Die Implementierung dieser OOP-Konzepte mit Traits macht Ihre Rust-Programme skalierbar, robust, wartbar und effizient.