Rust-Struct
In Rust können sowohl Structs als auch Tupel mehrere Datenelemente möglicherweise unterschiedlicher Typen zu einem Ganzen bündeln, aber jedes Mitglied und das Struct selbst haben einen Namen, sodass Sie sich beim Zugriff auf Mitglieder keine Indizes merken müssen. Tupel werden häufig für Ad-hoc-Übergaben verwendet, während Structs verwendet werden, um häufig genutzte Daten zu definieren. Jedes Mitglied eines Structs ist ein "Feld".
Struct-Definition
Dies ist eine Struct-Definition:
struct Site {
domain: String,
name: String,
nation: String,
found: u32
}Hinweis: Wenn Sie C/C++ gewohnt sind, denken Sie daran, dass in C die Struct-Anweisung nur zur Definition verwendet wird, sie kann keine Instanzen deklarieren, und sie hat kein;Symbol, und nach jeder Felddefinition verwenden Sie,zur Trennung.
Struct-Instanz
Rust ist an vielen Stellen von JavaScript beeinflusst. Beim Instanziieren einer Struktur verwendet es diekey: value-Syntax des JSON-Objekts, um die Definition zu erreichen:
Beispiel
domain: String::from("www.example.com"),
name: String::from("EXAMPLE"),
nation: String::from("China"),
found: 2013
};
Wenn du JSON-Objekte nicht kennst, kannst du sie ignorieren und dir einfach das Format merken:
Struct class name {
field name : field value,
...
}Der Vorteil dabei ist, dass es das Programm nicht nur intuitiver macht, sondern auch, dass die Member-Werte nicht in der Reihenfolge eingegeben werden müssen, in der sie definiert wurden.
Wenn die zu instanziierende Struktur Feldnamen hat, die mit vorhandenen Variablennamen übereinstimmen, kannst du die Schreibweise vereinfachen:
Beispiel
let domain = String::from("www.example.com");
let name = String::from("EXAMPLE");
let example = Site {
domain, // entspricht domain: domain,
name, // entspricht name: name,
nation: String::from("China"),
traffic: 2013
};
Es gibt eine Situation: Du möchtest eine neue Struct-Instanz erstellen, bei der die meisten Eigenschaften auf dieselben Werte wie bei einem vorhandenen Struct gesetzt werden müssen und du nur ein oder zwei Feldwerte ändern musst. Du kannst die Struct-Update-Syntax verwenden:
let site = Site {
domain: String::from("www.example.com"),
name: String::from("EXAMPLE"),
..example
};Hinweis:..exampleDanach darf kein Komma stehen. Diese Syntax erlaubt es nicht, eine andere Struct-Instanz exakt ohne Änderungen zu kopieren; das heißt, du musst mindestens den Wert eines Feldes festlegen, bevor du auf die Werte einer anderen Instanz verweist.
Tupel-Struktur
Es gibt eine einfachere Möglichkeit, Structs zu definieren und zu verwenden:Tupel-Struktur。
Eine Tupel-Struktur ist eine Struktur, die die Form eines Tupels hat.
Der Unterschied zu einem Tupel besteht darin, dass es einen Namen und ein festes Typformat hat. Es existiert, um einfache Daten zu handhaben, die einen definierten Typ benötigen (für häufige Verwendung), ohne zu komplex zu sein:
struct Color(u8, u8, u8); struct Point(f64, f64); let black = Color(0, 0, 0); let origin = Point(0.0, 0.0);
"Color" und "Punktkoordinaten" sind zwei häufig verwendete Datentypen, aber wenn du beim Instanziieren geschweifte Klammern und zwei Namen schreibst, opferst du Bequemlichkeit zugunsten der Lesbarkeit. Rust lässt dieses Problem nicht ungelöst. Tupel-Struktur-Objekte werden genauso wie Tupel verwendet, wobei der Zugriff über . und Indizes erfolgt:
Beispiel
struct Color(u8, u8, u8);
struct Point(f64, f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);
println!("black = ({}, {}, {})", black.0, black.1, black.2);
println!("origin = ({}, {})", origin.0, origin.1);
}
Ausgabe:
black = (0, 0, 0) origin = (0, 0)
Struct-Eigentümerschaft
Ein Struct muss die Werte seiner Felder besitzen, denn wenn das Struct den Gültigkeitsbereich verlässt, gibt es alle seine Felder frei.
Deshalb verwenden die Beispiele in diesem Kapitel den Typ String statt &str.
Aber das bedeutet nicht, dass Referenzfelder nicht in Structs definiert werden können; dies erfordert den "Lebensdauer"-Mechanismus.
Aber das Konzept der "Lebensdauer" ist jetzt schwer zu erklären, daher kann es erst in späteren Kapiteln erklärt werden.
Structs ausgeben
Beim Debuggen ist es sehr nützlich, eine vollständige Struct-Instanz anzuzeigen. Aber manuell ein Format zu schreiben wäre sehr umständlich. Deshalb bietet Rust eine bequeme Möglichkeit, ein ganzes Struct auszugeben:
Beispiel
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("rect1 is {:?}", rect1);
}
Wie in der ersten Zeile gezeigt: Importieren Sie unbedingt die Debug-Bibliothek#[derive(Debug)], dann können Sie in den Makros println und print den{:?}Platzhalter verwenden, um ein ganzes Struct auszugeben:
rect1 is Rectangle { width: 30, height: 50 }
Wenn es viele Attribute gibt, können Sie einen anderen Platzhalter verwenden{:#?} 。
Ausgabe:
rect1 is Rectangle {
width: 30,
height: 50
}
Struct-Methoden
Methoden ähneln Funktionen, außer dass sie verwendet werden, um mit Struct-Instanzen zu arbeiten.
Wenn Sie objektorientierte Sprachen studiert haben, müssen Sie wissen, dass Funktionen normalerweise in Klassendefinitionen platziert werden und innerhalb der Funktion "this" verwenden, um auf die Instanz zu verweisen, auf der gearbeitet wird.
Rust ist keine objektorientierte Sprache, was man an der Innovation seines Ownership-Mechanismus erkennen kann. Die wertvollen Ideen der objektorientierten Programmierung können jedoch in Rust umgesetzt werden.
Der erste Parameter einer Struct-Methode muss &self sein, und sein Typ muss nicht deklariert werden, weil self kein Stil, sondern ein Schlüsselwort ist.
Berechnen Sie die Fläche eines Rechtecks:
Beispiel
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("die Fläche von rect1 ist {}", rect1.area());
}
Ausgabe:
rect1's area is 1500
Beachten Sie, dass Sie beim Aufrufen einer Struct-Methode self nicht angeben müssen; dies dient der Bequemlichkeit.
Ein Beispiel mit mehreren Parametern:
Beispiel
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn wider(&self, rect: &Rectangle) -> bool {
self.width > rect.width
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
let rect2 = Rectangle { width: 40, height: 20 };
println!("{}", rect1.wider(&rect2));
}
Ausgabe:
false
Dieses Programm berechnet, ob rect1 breiter als rect2 ist.
Assoziierte Funktionen von Structs
Der Grund, warum "Struct-Methoden" nicht "Struct-Funktionen" genannt werden, ist, dass der Name "Funktion" für Funktionen reserviert ist, die sich in einem impl-Block befinden, aber keinen &self-Parameter haben.
Solche Funktionen hängen nicht von einer Instanz ab, aber um sie zu verwenden, muss man angeben, in welchem impl-Block sie sich befinden.
Die ständig verwendeteString::from-Funktion ist eine "assoziierte Funktion".
Beispiel
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn create(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
}
fn main() {
let rect = Rectangle::create(30, 50);
println!("{:?}", rect);
}
Ausgabe:
Rectangle { width: 30, height: 50 }
Tipp:Der impl-Block eines Structs kann mehrfach geschrieben werden; der Effekt entspricht dem Verketten ihrer Inhalte!
Unit-Struct
Ein Struct kann als Symbol ohne jegliche Mitglieder dienen:
struct UnitStruct;
Wir nennen dieses Struct ohne Rumpf ein Unit-Struct.
Andere Erweiterungen