Rust-Grundsyntax
Variablen, grundlegende Typen, Funktionen, Kommentare und Kontrollfluss sind Programmierkonzepte, die in fast jeder Programmiersprache zu finden sind.
Diese grundlegenden Konzepte werden in jedem Rust-Programm vorhanden sein. Wenn Sie sie früh lernen, können Sie die Verwendung von Rust so schnell wie möglich erlernen.
Variablen
Zunächst einmal muss angemerkt werden, dass Rust eine stark typisierte Sprache ist, aber die Fähigkeit besitzt, Variablentypen automatisch abzuleiten. Dies kann leicht mit schwach typisierten Sprachen verwechselt werden.
In Rust sind Variablen standardmäßig unveränderlich, es sei denn, sie werden mit dem Schlüsselwort `mut` als veränderlich deklariert.
let a = 123; // 不可变变量 let mut b = 10; // 可变变量
Um eine Variable zu deklarieren, musst du daslet-Schlüsselwort verwenden. Zum Beispiel:
let a = 123;
Entwickler, die nur JavaScript gelernt haben, reagieren sehr empfindlich auf diese Aussage, während Entwickler, die nur C gelernt haben, sie kaum verstehen können.
Nach dieser Deklaration sind die folgenden drei Codezeilen alle verboten:
a = "abc"; a = 4.56; a = 456;
Der Fehler in der ersten Zeile ist, dass nach der Deklaration von `a` als 123 `a` als Integer bestimmt ist und man ihm keinen String-Wert zuweisen kann.
Der Fehler in der zweiten Zeile ist, dass eine automatische Konvertierung numerische Präzision verlieren würde, und Rust erlaubt keine automatischen Typkonvertierungen, die Präzision verlieren.
Der Fehler in der dritten Zeile ist, dass `a` keine veränderliche Variable ist.
Die ersten beiden Fehler sind leicht zu verstehen, aber was bedeutet der dritte? Ist `a` denn keine Variable?
Dies hängt mit Rusts Design für hohe Nebenläufigkeitssicherheit zusammen: Auf Sprachebene wird versucht, die Situationen zu minimieren, in denen Variablenwerte geändert werden können. Der Wert von `a` ist also unveränderlich. Das bedeutet aber nicht, dass `a` keine „Variable“ ist (das englische Wort `variable`); die offizielle Dokumentation nennt Variablen wie `a` „unveränderliche Variablen“.
Wenn ein Teil unseres Programms unter der Annahme läuft, dass sich ein Wert niemals ändert, während ein anderer Teil unseres Codes diesen Wert ändert, dann verhält sich der erste Teil möglicherweise nicht wie beabsichtigt. Fehler, die dadurch entstehen, sind später schwer zu finden. Das ist der Grund, warum Rust diesen Mechanismus entwickelt hat.
Natürlich benötigt man zum „Veränderlichmachen“ einer Variable nur dasmut-Schlüsselwort.
let mut a = 123; a = 456;
Dieses Programm ist korrekt.
Unterschied zwischen Konstanten und unveränderlichen Variablen
Da unveränderliche Variablen unveränderlich sind, sind sie dann nicht einfach Konstanten? Warum werden sie Variablen genannt?
Es gibt dennoch einen Unterschied zwischen Variablen und Konstanten. In Rust ist das folgende Programm gültig:
let a = 123; // 可以编译,但可能有警告,因为该变量没有被使用 let a = 456;
Aber wenn `a` eine Konstante ist, ist es ungültig:
const a: i32 = 123; let a = 456;
Der Wert einer Variablen kann "neu gebunden" werden, aber er kann nicht von selbst geändert werden, bevor er "neu gebunden" wird. Dies stellt sicher, dass der Compiler innerhalb jedes Bereichs nach einer "Bindung" die Programmlogik vollständig nachvollziehen kann. Obwohl Rust automatische Typinferenz hat, ist es in manchen Fällen bequemer, den Typ anzugeben:
let a: u64 = 123;
Hier wird `a` als vorzeichenlose 64-Bit-Ganzzahlvariable deklariert. Wenn der Typ nicht deklariert würde, würde `a` automatisch als vorzeichenbehaftete 32-Bit-Ganzzahlvariable abgeleitet, was einen erheblichen Einfluss auf den Wertebereich hat, den `a` annehmen kann.
Datentypen
Rust ist eine statisch typisierte Sprache. Beim Deklarieren von Variablen können Sie Typen explizit angeben, aber normalerweise können Sie sich auf die Typinferenz verlassen.
Basistypen:i32 (32-Bit-Ganzzahl mit Vorzeichen), u32 (32-Bit-Ganzzahl ohne Vorzeichen), f64 (64-Bit-Gleitkommazahl), bool (boolescher Wert), char (Zeichen)
Beispiel
let y: f64 = 3.14;
let is_true: bool = true;
let letter: char = 'A';
Funktionen
Rust-Funktionen werden mit demfnSchlüsselwort definiert, und der Rückgabetyp wird mit dem Pfeilsymbol angegeben->.
Beispiel
a + b
}
Wenn eine Funktion keinen Rückgabewert hat, ist der Typ standardmäßig()(d. h. das leere Tupel).
Kontrollfluss
`if`-Ausdruck
Beispiel
if number < 5 {
println!("kleiner als 5");
} else {
println!("größer oder gleich 5");
}
`loop`-Schleife:`loop` ist eine Endlosschleife in Rust; du kannst `break` verwenden, um die Schleife zu verlassen.
Beispiel
loop {
counter += 1;
if counter == 10 {
break;
}
}
`while`-Schleife
Beispiel
while number != 0 {
println!("{}!", number);
number -= 1;
}
`for`-Schleife
Beispiel
println!("{}!", number);
}
Eigentümerschaft
Eigentümerschaft in Rust ist ein einzigartiger Speicherverwaltungsmechanismus. Zu seinen Kernkonzepten gehören Eigentümerschaft, Ausleihen und Referenzen.
Eigentümerschaftsregeln:
- Jeder Wert in Rust hat einen einzigen Eigentümer.
- Jeder Wert kann zu jedem beliebigen Zeitpunkt nur einen Eigentümer haben.
- Wenn der Eigentümer den Gültigkeitsbereich verlässt, wird der Wert freigegeben.
let s1 = String::from("hello");
let s2 = s1; // s1 的所有权被转移给了 s2
// println!("{}", s1); // 此处编译会报错,因为 s1 已不再拥有该值Ausleihen und Referenzen:Ausleihen ermöglicht es Ihnen, auf Daten zu verweisen, ohne Eigentümerschaft zu übernehmen, umgesetzt durch das&-Symbol.
fn main() {
let s = String::from("hello");
let len = calculate_length(&s); // 借用
println!("The length of '{}' is {}.", s, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
Strukturen
Strukturen werden verwendet, um benutzerdefinierte Typen zu erstellen, und ihre Felder können mehrere Datentypen enthalten.
Beispiel
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
let user1 = User {
username: String::from("someusername"),
email: String::from("[email protected]"),
sign_in_count: 1,
active: true,
};
Aufzählungen
Aufzählungen ermöglichen es dir, einen von mehreren möglichen Datentypen zu definieren.
Beispiel
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
Musterabgleich (match)
`match` ist ein mächtiges Werkzeug zur Kontrollflusssteuerung in Rust, ähnlich einer `switch`-Anweisung.
Beispiel
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
Fehlerbehandlung
Rust hat zwei Hauptwege der Fehlerbehandlung:Result<T, E>undOption<T>。
Ergebnis:
Beispiel
OK(T),
Err(E),
}
fn divide(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Division by zero"))
} else {
OK(a / b)
}
}
Option:
Beispiel
if index < vec.len() {
Some(vec[index])
} else {
Keine
}
}
Lebensdauern von Eigentümerschaft und Borrowing
Rust verwendet Lebensdauern, um sicherzustellen, dass Referenzen gültig sind. Lebensdauer-Annotationen werden durch'ausw. gekennzeichnet, aber in üblichen Fällen leitet der Compiler sie automatisch ab.
Beispiel
if x.len() > y.len() {
x
} else {
y
}
}
Shadowing
Das Konzept des Shadowings unterscheidet sich von "Überschreiben" oder "Überladen" in anderen objektorientierten Sprachen. Shadowing ist das, was früher "Rebinding" genannt wurde; die Anführungszeichen wurden verwendet, um das Konzept zu ersetzen, bevor es eingeführt wurde.
Shadowing bezeichnet den Mechanismus, durch den der Name einer Variable wiederverwendet werden kann:
Beispiel
let x = 5;
let x = x + 1;
let x = x * 2;
println!("The value of x is: {}", x);
}
Die Ausgabe dieses Programms ist:
The value of x is: 12
Shadowing ist nicht dasselbe Konzept wie die Zuweisung an eine veränderliche Variable. Shadowing bedeutet, denselben Namen zu verwenden, um eine andere variable Entität darzustellen, und ihr Typ, ihre Veränderbarkeit und ihr Wert können sich alle ändern. Die Zuweisung an eine veränderliche Variable kann jedoch nur ihren Wert ändern.
let mut s = "123"; s = s.len();
Dieses Programm führt zu einem Fehler: Man kann einer String-Variable keinen Ganzzahlwert zuweisen.
Andere Erweiterungen