Schnell wie C, aber speichersicher dank Ownership
Ausführen: Rust über rustup.rs installieren. Dann cargo new hallo, in den Ordner wechseln und cargo run ausführen. Einzelne Datei: rustc main.rs && ./main.
null und keine Ausnahmen: Option und Resultcargo baut, testet und verwaltet Pakete; rustc ist der Compilercargo new hallo # neues Projekt (Ordner mit Cargo.toml und src/main.rs)
cargo run # bauen und starten
cargo build --release # optimiert bauen
cargo test # Tests ausführen
cargo check # nur prüfen, schnell
cargo add serde # Abhängigkeit hinzufügen
cargo fmt, cargo clippy # formatieren, prüfenlet (unveränderlich) und let mut; Shadowing legt neue Variablen ani32, u8, f64, bool, char, &str, String, Tupel, Arrays, Vec<T>as, into, try_from{} Display, {:?} Debug, {name} Inline-Variablenchecked_*/wrapping_*/saturating_* steuern Überlaufverhaltenfn main() {
let name = "Mia"; // unveränderlich (Standard)
let mut punkte = 0; // veränderlich
punkte += 10;
let alter: u32 = 17; // Typ ausdrücklich
const MAX: u32 = 100; // Konstante: immer Typ nötig
// Shadowing: neue Variable mit demselben Namen
let x = 5;
let x = x * 2;
let x = format!("{x} Stück");
println!("{name} hat {punkte} Punkte, ist {alter}, Max {MAX}");
println!("{x}");
println!("{} + {} = {}", 3, 4, 3 + 4);
println!("{:>6}|{:<6}|{:^6}|{:06.2}|{:#x}|{:#b}", "ab", "cd", "ef", 3.14159, 255, 5);
println!("{0} {1} {0} {n}", "a", "b", n = 5);
println!("{:?} {:?}", (1, "zwei"), vec![1, 2, 3]);
}if und match sind Ausdrücke und liefern Wertebool sein, ohne Klammernfor x in iterator, while, loop (mit break wert)1..5 (ohne Ende), 1..=5 (mit Ende)match prüft Muster und erzwingt Vollständigkeit; _ fängt den Restif let, while let, let else, matches! für Einzelmusterfn main() {
let punkte = 73;
if punkte >= 90 {
println!("sehr gut");
} else if punkte >= 50 {
println!("bestanden");
} else {
println!("nicht bestanden");
}
// if liefert einen Wert (kein ?: nötig)
let status = if punkte >= 50 { "bestanden" } else { "durchgefallen" };
println!("{status}");
let zahl = 7;
let art = if zahl % 2 == 0 { "gerade" } else { "ungerade" };
println!("{zahl} ist {art}");
}fn name(param: Typ) -> Rückgabetyp { ... }; der letzte Ausdruck ohne ; ist der Rückgabewertreturn für frühes Verlassen; Tupel liefern mehrere Werte|x| x + 1 fangen Variablen ein; move übergibt den Besitzfn(i32) -> i32, impl Fn(...), Box<dyn Fn(...)>const fn rechnet zur Übersetzungszeitfn addiere(a: i32, b: i32) -> i32 {
a + b // letzter Ausdruck ohne Semikolon ist der Rückgabewert
}
fn gruss(name: &str) { // kein Rückgabetyp: gibt () zurück
println!("Hallo {name}!");
}
fn teile(a: i32, b: i32) -> (i32, i32) {
(a / b, a % b) // Tupel als Mehrfach-Rückgabe
}
fn betrag(x: i32) -> i32 {
if x < 0 { return -x; } // früher Rückgabe mit return
x
}
fn main() {
println!("{}", addiere(3, 4));
gruss("Mia");
let (q, r) = teile(17, 5);
println!("{q} {r} {}", betrag(-9));
}Copy-Typen); .clone() kopiert tief&T (viele Leser) oder &mut T (ein Schreiber), nie beides gleichzeitig&str, &[T] sind Sichten; Lebensdauern ('a) erklären, wie lange Referenzen gültig sindfn main() {
{
let s = String::from("Hallo"); // s besitzt den Text auf dem Heap
println!("{s}");
} // hier endet s: der Speicher wird automatisch freigegeben
}struct bündelt Felder; impl gibt Methoden (&self, &mut self, self) und Typ::neu()-Funktionen#[derive(Debug, Clone, PartialEq)] erzeugt Standardverhaltenenum-Varianten tragen Daten; match erzwingt Vollständigkeitnull: Option<T> mit Some/NoneDisplay mit write! für schöne Ausgaben#[derive(Debug, Clone, PartialEq)] // Debug-Ausgabe, Kopieren, Vergleichen automatisch
struct Person {
name: String,
alter: u32,
}
impl Person {
fn neu(name: &str, alter: u32) -> Self { // "Konstruktor" (Konvention: new)
Person { name: name.to_string(), alter }
}
fn vorstellen(&self) -> String { // &self: leiht sich die Person
format!("{} ({})", self.name, self.alter)
}
fn geburtstag(&mut self) { // &mut self: ändert die Person
self.alter += 1;
}
}
fn main() {
let mut mia = Person::neu("Mia", 17);
mia.geburtstag();
println!("{}", mia.vorstellen());
println!("{mia:?}");
println!("{mia:#?}");
let kopie = Person { name: "Tom".into(), ..mia.clone() }; // Struct-Update-Syntax
println!("{} {}", kopie.vorstellen(), mia == kopie);
}Result<T, E> hat Ok(T) und Err(E); Fehler sind Werte, keine Ausnahmen? reicht Fehler weiter und wandelt sie über From umBox<dyn Error> in Programmen, eigene Fehler-Enums in Bibliotheken (oder thiserror/anyhow)map, map_err, unwrap_or, and_then verarbeiten Ergebnissepanic! und unwrap nur bei Programmierfehlern und unmöglichen Fällenenum Result<T, E> {
Ok(T), // Erfolg mit Wert
Err(E), // Fehler mit Beschreibung
}Vec<T>: push, pop, insert, remove, sort, iter, get (sicher) vs v[i] (Panic bei Fehlindex)HashMap<K, V>: insert, get, entry().or_insert(); Reihenfolge ist zufälligBTreeMap/BTreeSet sind sortiert, VecDeque für Warteschlangen, BinaryHeap für Prioritätenfor x in &v leiht aus, for x in v verbraucht die Collection.entry() für "einfügen oder ändern"fn main() {
let mut v = vec![5, 3, 9];
v.push(1);
v.insert(1, 42);
println!("{v:?} {} {:?} {:?}", v.len(), v.first(), v.get(10));
println!("{} {}", v[0], v.contains(&9));
let letztes = v.pop();
v.remove(0);
println!("{letztes:?} {v:?}");
v.sort();
v.reverse();
println!("{v:?}");
v.extend([7, 8]);
v.retain(|&x| x != 8);
v.dedup();
println!("{v:?} {:?} {:?}", v.iter().max(), v.iter().sum::<i32>());
let mut leer: Vec<String> = Vec::new();
leer.push("a".to_string());
let mit_kapazitaet: Vec<u8> = Vec::with_capacity(100);
println!("{} {}", leer.len(), mit_kapazitaet.capacity() >= 100);
println!("{:?} {:?}", &v[1..3], v.chunks(2).collect::<Vec<_>>());
println!("{:?}", v.windows(2).map(|w| w[1] - w[0]).collect::<Vec<_>>());
}impl Trait for Typ setzt es um, Standardmethoden sind möglichT: Display, where) werden zur Übersetzungszeit aufgelöstimpl Trait (statisch) und Box<dyn Trait> (dynamisch) für unterschiedliche Fälle#[derive(Debug, Clone, PartialEq, Default)] erledigt StandardfälleDrop, From, Add sind wichtige Standard-Traitstrait Tier {
fn name(&self) -> String;
fn laut(&self) -> String;
fn vorstellen(&self) -> String { // Standardimplementierung
format!("{} macht {}", self.name(), self.laut())
}
}
struct Hund;
struct Katze { name: String }
impl Tier for Hund {
fn name(&self) -> String { "Hund".to_string() }
fn laut(&self) -> String { "Wuff".to_string() }
}
impl Tier for Katze {
fn name(&self) -> String { self.name.clone() }
fn laut(&self) -> String { "Miau".to_string() }
fn vorstellen(&self) -> String { format!("{} schnurrt und sagt {}", self.name, self.laut()) }
}
fn main() {
let tiere: Vec<Box<dyn Tier>> = vec![Box::new(Hund), Box::new(Katze { name: "Mimi".into() })];
for t in &tiere {
println!("{}", t.vorstellen());
}
}collect, sum, for ... führen sie ausiter() leiht, iter_mut() leiht veränderbar, into_iter() verbrauchtmap, filter, take, skip, zip, enumerate, flatten, revsum, fold, any, all, find, position, collect, partitionIterator mit next() implementierenfn main() {
let v = vec![1, 2, 3];
let mut it = v.iter();
println!("{:?} {:?} {:?} {:?}", it.next(), it.next(), it.next(), it.next());
let quadrate: Vec<i32> = v.iter().map(|x| x * x).collect();
let gerade: Vec<&i32> = v.iter().filter(|x| **x % 2 == 0).collect();
let summe: i32 = v.iter().sum();
println!("{quadrate:?} {gerade:?} {summe}");
}Box<T> Heap, Rc<T> geteilter Besitz (ein Thread), Arc<T> (mehrere Threads)RefCell<T> / Mutex<T> für Veränderung bei geteiltem Besitz'a) beschreiben, wie lange Referenzen gültig sindthread::spawn mit move, join wartet; Channels (mpsc) schicken Nachrichten#[derive(Debug)]
enum Liste {
Element(i32, Box<Liste>),
Ende,
}
use Liste::{Element, Ende};
fn main() {
let b = Box::new(5);
println!("{} {}", b, *b + 1);
let l = Element(1, Box::new(Element(2, Box::new(Ende))));
println!("{l:?}");
}mod gliedert Code, pub macht öffentlich, use importiertcargo new/run/build/test/fmt/clippy sind die wichtigsten BefehleCargo.toml listet Abhängigkeiten (Crates von crates.io)#[test] und cargo test, Makros assert_eq! usw.anyhow/thiserror für Fehler, serde/tokio für den Alltagmod geometrie {
pub const PI: f64 = 3.14159;
pub struct Kreis {
pub radius: f64,
id: u32, // privat
}
impl Kreis {
pub fn neu(radius: f64) -> Self { Kreis { radius, id: 1 } }
pub fn flaeche(&self) -> f64 { PI * self.radius * self.radius }
pub fn id(&self) -> u32 { self.id }
}
pub mod hilfe {
pub fn runde(x: f64) -> f64 { (x * 100.0).round() / 100.0 }
}
}
use geometrie::{hilfe::runde, Kreis};
fn main() {
let k = Kreis::neu(2.0);
println!("{} {}", runde(k.flaeche()), k.id());
println!("{}", geometrie::PI);
}Option und Result ersetzen null und Exceptionsif x > 0 { ... } else if x == 0 { ... } else { ... }
let w = if a { 1 } else { 2 };
match wert { 1 => ..., 2 | 3 => ..., 4..=9 => ..., n if n < 0 => ..., _ => ... }
if let Some(x) = opt { ... }
let Some(x) = opt else { return };
while bedingung { ... }
loop { ... break wert; }
for i in 0..10 { ... } // 0..=10 inklusive