E0382
error[E0382]: use of moved value: `s1`
Wenn du einen heap-allozierten Wert (wie String oder Vec) einer anderen Variable zuweist, wird der Besitz auf die neue Variable übertragen. Das Original ist weg – du kannst es danach nicht mehr verwenden. Das ist Rusts Ownership-System, das Use-after-free-Bugs zur Kompilierzeit eliminiert.
❌ Broken
let s1 = String::from("hello");
let s2 = s1; // s1 moves into s2
println!("{}", s1); // ❌ E0382: s1 was moved✅ Fixed
let s1 = String::from("hello");
let s2 = s1.clone(); // deep copy — both stay valid
println!("{} {}", s1, s2); // ✅
// Or borrow instead of moving:
let s2 = &s1;
println!("{} {}", s1, s2); // ✅💡 Tip: Primitive Typen (i32, bool, char, f64) implementieren Copy und werden automatisch dupliziert. Heap-Typen (String, Vec, Box) werden verschoben.
E0502
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
Rust erlaubt entweder viele geteilte (&)-Referenzen ODER eine exklusive (&mut)-Referenz – niemals beides gleichzeitig. Wenn ein aktives unveränderliches Borrow besteht, kann kein mutablees Borrow genommen werden, bis das unveränderliche endet. Diese Regel eliminiert Data Races konstruktiv.
❌ Broken
let mut v = vec![1, 2, 3];
let first = &v[0]; // immutable borrow
v.push(4); // ❌ E0502: mutable borrow while immutable exists
println!("{}", first);✅ Fixed
let mut v = vec![1, 2, 3];
let first = v[0]; // copy the value out (i32 is Copy)
v.push(4); // ✅ no active borrow
println!("{}", first);
// Or restructure scope:
let mut v = vec![1, 2, 3];
{
let first = &v[0];
println!("{}", first);
} // first's borrow ends here
v.push(4); // ✅💡 Tip: Der Borrow Checker ist konservativ. Wenn er dich blockiert, versuche das println früher zu verschieben, den Wert statt zu leihen zu kopieren, oder .clone() zu verwenden.
E0499
error[E0499]: cannot borrow `v` as mutable more than once at a time
Es kann jeweils nur eine mutable Referenz (&mut) existieren. Das verhindert Data Races in Single-Threaded-Code und ist die grundlegende Regel, die Rusts Nebenläufigkeitsgarantien ermöglicht.
❌ Broken
let mut v = vec![1, 2, 3];
let a = &mut v;
let b = &mut v; // ❌ E0499: second mutable borrow
a.push(4);
b.push(5);
✅ Fixed
let mut v = vec![1, 2, 3];
{
let a = &mut v;
a.push(4);
} // a's borrow ends here
let b = &mut v; // ✅ now safe
b.push(5);💡 Tip: Verwende Scopes {}, um zu begrenzen, wie lange ein mutablees Borrow lebt. In der Praxis bedeutet dieser Fehler oft, die Logik umzustrukturieren, sodass Mutationen sequentiell erfolgen.
E0308
error[E0308]: mismatched types
expected `i32`, found `&i32`
Der Typ, den der Compiler inferiert oder erwartet, stimmt nicht mit dem überein, was du angegeben hast. Sehr häufig beim Iterieren (Iteratoren liefern Referenzen), wenn eine Funktion () statt eines Werts zurückgibt, oder beim Mischen von vorzeichenbehafteten und vorzeichenlosen Ganzzahlen.
❌ Broken
// Trailing semicolon returns () instead of i32:
fn double(n: i32) -> i32 {
n * 2; // ❌ E0308: returns () not i32
}
// Iterator reference confusion:
let nums = vec![1, 2, 3];
let sum: i32 = nums.iter().sum(); // needs type annotation✅ Fixed
fn double(n: i32) -> i32 {
n * 2 // ✅ no semicolon — expression returned
}
// Dereference in closures when iterating:
let nums = vec![1, 2, 3];
let doubled: Vec<i32> = nums.iter().map(|&x| x * 2).collect();
// ^ dereference the &i32💡 Tip: Ein abschließendes Semikolon in der letzten Zeile einer Funktion ändert stillschweigend den Rückgabetyp auf (). Das ist der häufigste Anfängerfehler in Rust.
E0277
error[E0277]: `MyType` doesn't implement `std::fmt::Display`
Der Typ implementiert ein erforderliches Trait nicht. Wird am häufigsten ausgelöst, wenn {} -Formatierung ohne Display verwendet wird, Typen ohne PartialOrd verglichen werden, oder Methoden aufgerufen werden, die ein bestimmtes Trait erfordern.
❌ Broken
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
println!("{}", p); // ❌ E0277: Point doesn't implement Display
println!("{:?}", p); // also fails — needs Debug✅ Fixed
#[derive(Debug)]
struct Point { x: i32, y: i32 }
let p = Point { x: 1, y: 2 };
println!("{:?}", p); // ✅ Debug via #[derive(Debug)]
// Implement Display manually for custom formatting:
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
println!("{}", p); // ✅💡 Tip: Füge #[derive(Debug)] für {:?}-Ausgabe hinzu. Für {}-Ausgabe implementiere std::fmt::Display manuell. Die meisten fehlenden Bounds sind Debug, Display, Clone, PartialEq oder PartialOrd.
E0106
error[E0106]: missing lifetime specifier
expected named lifetime parameter
Wenn eine Funktion eine Referenz zurückgibt und mehrere Referenzparameter hat, kann Rust nicht inferieren, von welcher Eingabe die Ausgabereferenz stammt. Du musst es mit Lifetime-Annotationen angeben.
❌ Broken
// Compiler doesn't know if the return borrows from x or y:
fn longest(x: &str, y: &str) -> &str { // ❌ E0106
if x.len() > y.len() { x } else { y }
}✅ Fixed
// 'a says: output lives no longer than the shorter input
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { // ✅
if x.len() > y.len() { x } else { y }
}
// Single input → no annotation needed (elision rule):
fn first_word(s: &str) -> &str { // ✅ lifetime elided
let bytes = s.as_bytes();
for (i, &b) in bytes.iter().enumerate() {
if b == b' ' { return &s[..i]; }
}
&s[..]
}💡 Tip: Lifetime-Annotationen sind Einschränkungen, keine Dauern. 'a bedeutet: ‚Die Ausgabe kann nicht länger leben als die Eingaben.' Die meisten Lifetimes werden inferiert (elided). Explizite brauchst du nur, wenn der Compiler die Beziehung nicht herausfinden kann.
E0596
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
Du hast versucht, eine Variable zu ändern, die nicht mit mut deklariert wurde. In Rust sind Variablen standardmäßig unveränderlich – der Compiler erzwingt dies, damit versehentliche Mutationen zur Kompilierzeit abgefangen werden.
❌ Broken
let x = 5;
x = 10; // ❌ E0596: x is immutable
let v = vec![1, 2, 3];
v.push(4); // ❌ E0596: v is immutable
✅ Fixed
let mut x = 5; // ✅ mut makes it mutable
x = 10;
let mut v = vec![1, 2, 3];
v.push(4); // ✅
💡 Tip: Füge mut nach let hinzu. Füge mut nur hinzu, wenn die Variable sich wirklich ändern muss – Unveränderlichkeit als Standard fängt Bugs ab und macht Code leichter nachvollziehbar.
E0384
error[E0384]: cannot assign twice to immutable variable `x`
Ähnlich wie E0596, aber ausgelöst durch eine zweite Zuweisung statt eines Methodenaufrufs. Die Variable wurde ohne mut deklariert, du hast aber versucht, sie neu zuzuweisen.
❌ Broken
let x = 5;
x = 10; // ❌ E0384
✅ Fixed
let mut x = 5;
x = 10; // ✅
// Shadowing is another option if you want to "replace" the variable:
let x = 5;
let x = 10; // ✅ shadowing — creates a new binding named x
💡 Tip: Shadowing (let x = ...) und Mutation (mut x = ...) sehen ähnlich aus, sind aber unterschiedlich: Shadowing erstellt eine neue Variable (und kann den Typ ändern), Mutation modifiziert dieselbe Bindung.
E0507
error[E0507]: cannot move out of `*s` which is behind a shared reference
Du hast versucht, einen Wert aus einer Referenz heraus zu verschieben. Du kannst über eine &T keine Eigenverantwortung übernehmen – die Referenz besitzt die Daten nicht.
❌ Broken
fn print_name(s: &String) {
let owned = *s; // ❌ E0507: can't move out of &String
println!("{}", owned);
}✅ Fixed
fn print_name(s: &String) {
let owned = s.clone(); // ✅ clone the data
println!("{}", owned);
}
// Or just use the reference directly:
fn print_name(s: &String) {
println!("{}", s); // ✅ no need to own it
}💡 Tip: Wenn du den Wert nur lesen musst, verwende die Referenz direkt. Wenn du eine eigene Kopie brauchst, rufe .clone() auf. Wenn du Ownership benötigst, ändere den Parameter so, dass T statt &T genommen wird.
E0004
error[E0004]: non-exhaustive patterns: `None` not covered
Ein match-Ausdruck muss jeden möglichen Fall behandeln. Wenn irgendeine Variante unbehandelt bleibt, wird der Code nicht kompiliert. Das eliminiert eine ganze Klasse von Laufzeitfehlern, bei denen unbehandelte Fälle Abstürze verursachen.
❌ Broken
let opt: Option<i32> = Some(42);
match opt {
Some(n) => println!("{}", n),
// ❌ E0004: None not covered
}✅ Fixed
match opt {
Some(n) => println!("{}", n),
None => println!("nothing"), // ✅ exhaustive
}
// Use _ as a catch-all:
match opt {
Some(n) => println!("{}", n),
_ => {}, // ✅ handles everything else
}
// Or use if let for a single case:
if let Some(n) = opt {
println!("{}", n); // ✅ no else needed
}💡 Tip: Der Compiler sagt dir genau, welche Varianten fehlen. _ ist ein Catch-all. if let ist eine Kurzform, wenn du dich nur um ein Muster kümmerst.
E0072
error[E0072]: recursive type `List` has infinite size
Ein rekursiver Typ, bei dem jede Variante sich direkt selbst enthält, würde unendlich viel Speicher zur Allokation erfordern. Rust muss die Größe jedes Typs zur Kompilierzeit kennen. Die Lösung ist Indirektion über Box, das eine bekannte Zeigergröße hat.
❌ Broken
enum List {
Cons(i32, List), // ❌ E0072: infinite size
Nil,
}✅ Fixed
enum List {
Cons(i32, Box<List>), // ✅ Box has fixed pointer size (8 bytes)
Nil,
}
let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));💡 Tip: Box<T> ist der einfachste Heap-Zeiger. Er hat eine feste Größe (eine Zeigerbreite) unabhängig von T und durchbricht damit die rekursive Größenberechnung.
E0716
error[E0716]: temporary value dropped while borrowed
Du hast einen temporären Wert erstellt, eine Referenz darauf genommen, und der temporäre Wert wurde freigegeben, bevor die Referenz verwendet wurde. Die Referenz wäre hängend – sie würde auf freigegebenen Speicher zeigen.
❌ Broken
let s: &str = &String::from("hello")
.to_uppercase(); // ❌ E0716: temporary dropped
// Also common with chains:
let name = get_user().name; // if get_user() returns a temp✅ Fixed
// Bind the temporary to a variable first:
let upper = String::from("hello").to_uppercase();
let s: &str = &upper; // ✅ upper lives long enough
println!("{}", s);💡 Tip: Wenn du diesen Fehler bekommst, führe eine Variable ein, um den Zwischenwert zu halten. Die Lebensdauer einer let-Bindung erstreckt sich bis zum Ende des Blocks.
E0515
error[E0515]: cannot return value referencing local variable `local`
Du hast versucht, eine Referenz auf eine lokale Variable zurückzugeben. Wenn die Funktion zurückgibt, wird die lokale Variable freigegeben und hinterlässt eine hängende Referenz. Rust verhindert das zur Kompilierzeit.
❌ Broken
fn get_greeting() -> &str {
let s = String::from("hello");
&s // ❌ E0515: s is dropped when function returns
}✅ Fixed
// Return an owned value:
fn get_greeting() -> String {
String::from("hello") // ✅ caller owns it
}
// Or return a &'static str literal:
fn get_greeting() -> &'static str {
"hello" // ✅ lives for the entire program
}💡 Tip: Wenn du eine Referenz zurückgeben musst, muss sie von den Eingaben der Funktion stammen (aus einem Parameter leihen) oder 'static sein. Im Zweifelsfall gib einen eigenen Typ zurück (String, Vec, etc.).
E0369
error[E0369]: binary operation `>` cannot be applied to type `T`
Du hast einen Operator auf einem generischen Typ T verwendet, aber T hat kein Trait Bound, das das Existieren dieses Operators erfordert. Generischer Code muss explizit angeben, welche Operationen ein Typ unterstützt.
❌ Broken
fn largest<T>(list: &[T]) -> &T {
let mut biggest = &list[0];
for item in list {
if item > biggest { // ❌ E0369: T doesn't implement PartialOrd
biggest = item;
}
}
biggest
}✅ Fixed
fn largest<T: PartialOrd>(list: &[T]) -> &T { // ✅ add bound
let mut biggest = &list[0];
for item in list {
if item > biggest {
biggest = item;
}
}
biggest
}💡 Tip: Wenn du E0369 bekommst, sagt dir die Fehlermeldung, welches Trait du brauchst: PartialOrd für Vergleiche, Add für +, Display für {}, etc. Füge es als Bound hinzu: <T: TraitName>.
E0428
error[E0428]: the name `connect` is defined multiple times
Du hast zwei Elemente (Funktionen, Structs, Typen, etc.) mit demselben Namen im selben Scope definiert. Rust erlaubt das nicht – Namen müssen innerhalb eines Moduls eindeutig sein.
❌ Broken
fn connect() -> String { "tcp".into() }
fn connect() -> String { "udp".into() } // ❌ E0428: duplicate✅ Fixed
fn connect_tcp() -> String { "tcp".into() }
fn connect_udp() -> String { "udp".into() } // ✅ unique names
// Or use a parameter:
fn connect(protocol: &str) -> String { protocol.into() }💡 Tip: Das passiert auch mit use-Anweisungen, die konfligierende Namen importieren. Verwende as zum Umbenennen: use std::io::Error as IoError;
E0061
error[E0061]: this function takes 2 arguments but 3 arguments were supplied
Du hast eine Funktion mit mehr oder weniger Argumenten aufgerufen, als ihre Signatur deklariert. Rust unterstützt keine Standardparameter oder variadischen Funktionen (außer über Makros wie println!).
❌ Broken
fn add(a: i32, b: i32) -> i32 { a + b }
add(1, 2, 3); // ❌ E0061: 3 args, expected 2
add(1); // ❌ E0061: 1 arg, expected 2✅ Fixed
add(1, 2); // ✅
// For optional parameters, use Option:
fn greet(name: &str, title: Option<&str>) {
match title {
Some(t) => println!("{} {}", t, name),
None => println!("{}", name),
}
}
greet("Alice", None);
greet("Bob", Some("Dr."));💡 Tip: Rust hat keine Standardparameter. Verwende Option<T> für optionale Werte oder Builder-Structs für Funktionen mit vielen optionalen Feldern.
E0433
error[E0433]: failed to resolve: use of undeclared crate or module `HashMap`
Du hast einen Typ oder eine Funktion verwendet, der/die nicht im Scope ist. Für Standardbibliothekstypen außerhalb des Prelude (wie HashMap, BTreeMap, BufReader) brauchst du eine explizite use-Anweisung.
❌ Broken
let mut map = HashMap::new(); // ❌ E0433: HashMap not in scope
✅ Fixed
use std::collections::HashMap;
let mut map = HashMap::new(); // ✅
// Common imports:
use std::collections::{HashMap, HashSet, BTreeMap};
use std::io::{self, BufRead, Write};
use std::fmt;💡 Tip: Das Rust-Prelude importiert automatisch gängige Typen (Vec, String, Option, Result, etc.). Alles andere benötigt ein explizites use. Rust Analyzer / rust-analyzer schlägt den korrekten use-Pfad vor.
error: expected `;`, found `let`
error: expected expression, found keyword `fn`
Syntaxfehler – der Parser hat etwas Unerwartetes gefunden. Meist ein fehlendes Semikolon, ein nicht geschlossenes Trennzeichen, ein Tippfehler in einem Schlüsselwort oder ein fehl platzierter Ausdruck.
❌ Broken
fn main() {
let x = 5 // ❌ missing semicolon
let y = 10;
fn inner() {} // ❌ nested fn needs to be at statement level
x + y // if this is a statement, not a return, add ;
}✅ Fixed
fn main() {
let x = 5; // ✅ semicolon added
let y = 10;
fn helper() {} // ✅ nested fn is valid in Rust
println!("{}", x + y);
}💡 Tip: Rusts Fehlermeldungen zeigen fast immer auf die richtige Zeile. Wenn ein Semikolon-Fehler falsch erscheint, prüfe die Zeile darüber – ein fehlendes ; in der vorherigen Anweisung bringt den Parser in einen seltsamen Zustand.
error[E0275]: overflow evaluating the requirement `Box<T>: Sized`
Der Compiler geriet in eine Endlosschleife beim Versuch, ein Trait Bound zu beweisen. Meist verursacht durch eine rekursive Trait-Implementierung oder einen Typ, der versucht, ein Trait zu implementieren, das sich selbst erfordert.
❌ Broken
// Generic function calling itself with an incompatible bound:
fn process<T: Clone>(x: T) {
process(x.clone()); // infinite recursion in type inference
}✅ Fixed
// Add a base case or restructure logic:
fn process(x: String) {
if x.is_empty() { return; }
process(x[1..].to_string());
}💡 Tip: Dieser Fehler deutet fast immer auf einen rekursiven Typ oder eine Trait-Bound-Schleife hin. Vereinfache die Trait-Einschränkungen oder füge explizite Typparameter hinzu.
error[E0425]: cannot find value `x` in this scope
Du hast auf eine Variable verwiesen, die im aktuellen Scope nicht existiert. Häufige Ursachen: Tippfehler im Variablennamen, Variable in einem inneren Block deklariert der bereits geendet hat, oder eine Schleifenvariable außerhalb der Schleife verwendet.
❌ Broken
{
let x = 5;
}
println!("{}", x); // ❌ x is out of scope
for i in 0..10 { }
println!("{}", i); // ❌ i only lives inside the for loop✅ Fixed
let x = 5; // declare outside the block
{
println!("{}", x); // ✅ x is in scope
}
println!("{}", x); // ✅ still in scope
// Save the last loop value explicitly:
let mut last = 0;
for i in 0..10 { last = i; }
println!("{}", last); // ✅💡 Tip: Rust-Scoping ist blockbasiert. Variablen existieren nur von ihrer Deklaration bis zum Ende ihres umschließenden Blocks. Verschiebe die Deklaration nach oben, wenn du einen weiteren Scope benötigst.