Rust-Fehler E0308: mismatched types (Typen passen nicht)
Fehler E0308 bedeutet: Rust hat einen Wert von einem bestimmten Typ erwartet, du hast aber einen Wert von einem anderen Typ hingeschrieben. Das ist wahrscheinlich der Fehler, den du in Rust am häufigsten siehst. Zum Glück nennt dir die Meldung fast immer beide Typen, deshalb ist er meist schnell behoben. (Du suchst einen anderen Fehler? In der Übersicht der Compilerfehler findest du alle.)
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0308]: mismatched types --> src/main.rs:6:29 |6 | let user = User { name: "Ferris" }; | ^^^^^^^^ expected `String`, found `&str` |help: try using a conversion method |6 | let user = User { name: "Ferris".to_string() }; | ++++++++++++Dieses Programm erzeugt den Fehler:
struct User { name: String,}
fn main() { let user = User { name: "Ferris" }; println!("{}", user.name);}Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Jede E0308-Meldung hat dieselbe Form: expected A, found B – also „erwartet A, gefunden B“.
- Expected ist der Typ, den Rust an dieser Stelle braucht. Er kommt von woanders her: aus einer Typannotation, aus dem Parameter- oder Rückgabetyp einer Funktion, aus einem Struct-Feld oder aus einem anderen Zweig eines
if/match. - Found ist der Typ des Werts, den du dort tatsächlich geschrieben hast.
Im Beispiel ist das Feld name als String deklariert, also erwartet Rust einen String. Aber "Ferris" ist ein String-Literal, und das hat den Typ &str. Die beiden sind verwandt, aber nicht derselbe Typ.
Achte auch auf die help:-Zeilen. Bei E0308 schlägt dir der Compiler oft genau die richtige Lösung vor, wie oben .to_string().
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“Rust wandelt Typen nie heimlich um. In manchen Sprachen wird eine Zahl stillschweigend zu einem String, oder eine große Zahl wird unbemerkt abgeschnitten, damit sie in einen kleineren Typ passt. Solche versteckten Umwandlungen verursachen echte Bugs: verlorene Daten, falsche Ergebnisse, Abstürze weit weg vom eigentlichen Fehler.
Deshalb macht Rust jede Umwandlung im Code sichtbar. Das ist ein bisschen mehr Tipparbeit. Dafür siehst du später beim Lesen genau, wo ein Wert seinen Typ wechselt und ob dieser Schritt schiefgehen kann. Die Typen selbst findest du unter Datentypen.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Jede Lösung unten beginnt mit der passenden Form der Fehlermeldung. So kannst du direkt zu der springen, die zu deiner passt.
Lösung 1: Das Semikolon am Ende entfernen
Abschnitt betitelt „Lösung 1: Das Semikolon am Ende entfernen“error[E0308]: mismatched types --> src/main.rs:1:46 |1 | fn total_price(price: u32, quantity: u32) -> u32 { | ----------- ^^^ expected `u32`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression2 | price * quantity; | - help: remove this semicolon to return this valueSiehst du found (), dann schau dir die letzte Zeile der Funktion an. In Rust ist der letzte Ausdruck eines Blocks ohne Semikolon sein Rückgabewert. Mit ; wird daraus eine Anweisung, und die Funktion gibt stattdessen () zurück (den Typ für „nichts“). Der Compiler sagt es auch: Der Funktionsrumpf hat keinen Ausdruck am Ende, also gibt er () zurück. Lösch das Semikolon:
fn total_price(price: u32, quantity: u32) -> u32 { price * quantity // kein Semikolon: dieser Wert wird zurückgegeben}
fn main() { println!("Gesamt: {}", total_price(250, 3));}Ausgabe:
Gesamt: 750Dasselbe passiert in if-Blöcken und in match-Armen. Mehr dazu unter Funktionen.
Lösung 2: Zwischen String und &str umwandeln
Abschnitt betitelt „Lösung 2: Zwischen String und &str umwandeln“String ist ein eigener, wachsender String. &str ist eine geliehene Ansicht auf einen Text. Die ganze Geschichte steht unter Strings. Die Umwandlung ist in beide Richtungen kurz:
&strzuString:.to_string()oderString::from(...).Stringzu&str: mit&ausleihen (oder.as_str()aufrufen).
Der zweite Fall zeigt sich als expected &str, found String, meistens wenn du einen String an eine Funktion übergibst, die &str nimmt.
struct User { name: String,}
fn greet(name: &str) { println!("Hallo, {name}!");}
fn main() { // &str -> String: .to_string() oder String::from() let user = User { name: "Ferris".to_string() };
// String -> &str: mit & ausleihen (oder .as_str() aufrufen) greet(&user.name); greet(user.name.as_str());
let mut tags: Vec<String> = Vec::new(); tags.push(String::from("rust")); println!("{tags:?}");}Ausgabe:
Hallo, Ferris!Hallo, Ferris!["rust"]Lösung 3: Zwischen Zahlentypen umwandeln
Abschnitt betitelt „Lösung 3: Zwischen Zahlentypen umwandeln“error[E0308]: mismatched types --> src/main.rs:3:22 |3 | let count: i32 = names.len(); | --- ^^^^^^^^^^^ expected `i32`, found `usize` | | | expected due to thisi32, i64, u32 und usize sind alles verschiedene Typen, und Rust mischt sie nicht. Längen und Indizes sind immer usize. Der Compiler zeigt dir mit „expected due to this“ auch, woher die Erwartung kommt: hier von der Annotation i32. Wähl eine Umwandlung:
.into()(oderi64::from(x)), wenn bei der Umwandlung nie Daten verloren gehen können, etwa voni32nachi64.i64::try_from(x)(oder.try_into()), wenn der Wert vielleicht nicht passt. Das gibt einResultzurück, und du entscheidest, was im Fehlerfall passiert.asist der schnelle Cast. Er schlägt nie fehl, schneidet aber Werte, die nicht passen, stillschweigend ab. Nimm ihn nur, wenn du weißt, dass der Wert klein ist.
fn average(total: i64, count: i64) -> i64 { total / count}
fn main() { let scores: Vec<i32> = vec![80, 95, 70]; let total: i32 = scores.iter().sum();
// i32 -> i64 passt immer, also reicht .into() let total: i64 = total.into();
// usize -> i64 passt vielleicht nicht, also fragt try_from erst nach let count = i64::try_from(scores.len()).unwrap();
println!("Durchschnitt: {}", average(total, count));
// `as` geht auch, schneidet aber Werte, die nicht passen, stillschweigend ab let players = scores.len() as i32; println!("{players} Spieler");}Ausgabe:
Durchschnitt: 813 SpielerOft ist es am einfachsten, stattdessen die Annotation zu ändern: let count: usize = names.len();. Die Seiten Typumwandlung und Konvertierungen gehen tiefer.
Lösung 4: In Some einpacken oder die Option auspacken
Abschnitt betitelt „Lösung 4: In Some einpacken oder die Option auspacken“error[E0308]: mismatched types --> src/main.rs:3:27 |3 | let position: usize = names.iter().position(|n| *n == "Ben"); | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found `Option<usize>` | | | expected due to thisOption<usize> ist kein usize. Es heißt „vielleicht ein usize, vielleicht nichts“. Diesen Konflikt gibt es in beide Richtungen:
- Expected
T, foundOption<T>: Du musst den Fall „nichts“ behandeln, mitmatch,if letoderunwrap_or(default). - Expected
Option<T>, foundT: Deine Funktion gibt eineOptionzurück, also pack den Wert ein:Some(10)statt10.
fn find_discount(code: &str) -> Option<u32> { if code == "SAVE10" { return Some(10); // T -> Option<T>: in Some einpacken } None}
fn main() { let names = vec!["Ana", "Ben", "Cy"];
// Option<T> -> T: den Fall „nichts gefunden“ behandeln ... match names.iter().position(|n| *n == "Ben") { Some(i) => println!("Ben steht an Position {i}"), None => println!("Ben ist nicht da"), }
// ... oder mit unwrap_or einen Standardwert wählen let discount: u32 = find_discount("HELLO").unwrap_or(0); println!("Rabatt: {discount} %");}Ausgabe:
Ben steht an Position 1Rabatt: 0 %Der Compiler schlägt dir vielleicht .expect("REASON") vor. Das funktioniert auch, lässt dein Programm aber abstürzen, wenn der Wert None ist. Nimm es also nur, wenn None wirklich nicht vorkommen kann. Siehe Option.
Lösung 5: Alle if/else- und match-Zweige auf denselben Typ bringen
Abschnitt betitelt „Lösung 5: Alle if/else- und match-Zweige auf denselben Typ bringen“error[E0308]: `if` and `else` have incompatible types --> src/main.rs:3:52 |3 | let label = if stock > 0 { "in stock" } else { stock }; | ---------- ^^^^^ expected `&str`, found integer | | | expected because of thisWenn if oder match einen Wert liefert, muss Rust dessen einen Typ kennen. Deshalb muss jeder Zweig denselben Typ liefern. Der erste Zweig legt die Erwartung fest, und der Fehler zeigt auf den Zweig, der nicht passt („if and else have incompatible types“ heißt „if und else haben unverträgliche Typen“). Bei match lautet die Meldung „match arms have incompatible types“. Bring den abweichenden Zweig auf Linie:
fn status_text(code: u16) -> String { match code { 200 => "OK".to_string(), 404 => "Nicht gefunden".to_string(), _ => format!("Unbekannter Code {code}"), // jeder Arm ist ein String }}
fn main() { let stock = 0; let label = if stock > 0 { "auf Lager" } else { "ausverkauft" }; // beide &str println!("{label}");
println!("{}", status_text(404)); println!("{}", status_text(418));}Ausgabe:
ausverkauftNicht gefundenUnbekannter Code 418Hier brauchte ein Arm format!, und das erzeugt einen String. Deshalb wurden die anderen Arme auch zu String. Siehe if/else und match.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“- Benutzereingaben lesen.
let age: u32 = input.trim();ergibt „expectedu32, found&str“. Text ist keine Zahl. Lösung: Parse ihn:let age: u32 = input.trim().parse().unwrap();(oder behandle den Fehler, siehe Result). - Literale in einen
Vec<String>schieben.tags.push("rust")ergibt „expectedString, found&str“. Lösung:tags.push("rust".to_string()), oder mach daraus einenVec<&str>, wenn die Strings alle Literale sind. - Rechnen mit gemischten Zahlentypen.
total + n, wobeitotaleini64undneini32ist, ergibt E0308 (und oft E0277 daneben). Lösung: Wandle zuerst eine Seite um:total + i64::from(n).
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0277: trait bound not satisfied: taucht oft neben E0308 auf, zum Beispiel wenn du ein
i64zu einemi32addierst. - E0599: no method found: Du hast eine Methode aufgerufen, die es für diesen Typ nicht gibt – oft, weil der Wert einen anderen Typ hat, als du dachtest.
- E0425: cannot find value in this scope: ein Name, den Rust überhaupt nicht kennt.
- Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Eine Funktion hat -> i32, aber der Fehler sagt „expected i32, found ()“. Was ist die wahrscheinlichste Ursache?
2. Eine Funktion nimmt &str, und du hast let name = String::from("Ana");. Wie übergibst du den Wert?
3. Welche Umwandlung kann nie stillschweigend Daten verlieren?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0308 – Index der Rust-Fehlercodes (auf Englisch): die offizielle Erklärung dieses Fehlers.
- Funktionen mit Rückgabewerten – Die Programmiersprache Rust: warum ein Semikolon am Ende ändert, was eine Funktion zurückgibt.
- UTF-8-kodierten Text in Strings ablegen – Die Programmiersprache Rust: wie
Stringund&strzusammenhängen und wie du zwischen ihnen umwandelst. - Conversion – Rust by Example (auf Englisch):
From,Into,TryFromundTryIntomit kurzen Beispielen. Option– Doku der Standardbibliothek (auf Englisch): alle Methoden, um einen Wert aus einerOptionzu holen, etwaunwrap_orundmap.