Rust-Fehler E0614: type cannot be dereferenced (* ohne Referenz)
E0614 bedeutet: Du hast * vor etwas geschrieben, das keine Referenz ist, also gibt es nichts, dem Rust folgen könnte. Der Operator * heißt „geh zu dem Wert, auf den diese Referenz zeigt“. Ein einfaches u32, i32 oder Struct zeigt nirgendwohin: Es ist der Wert. Das passiert meistens in Closures und Schleifen, wo man leicht den Überblick verliert, ob man gerade ein &u32 oder ein u32 hat. rustc nennt dir in der Überschrift den echten Typ, und die Lösung ist fast immer, ein * zu löschen. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0614]: type `u32` cannot be dereferenced --> src/main.rs:3:64 |3 | let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` ist schon ein `u32` | ^^^^^^ can't be dereferencedAuf Deutsch: „Der Typ u32 kann nicht dereferenziert werden.“ Dereferenzieren heißt: mit * der Referenz zum Wert folgen.
Dieses Programm erzeugt den Fehler:
fn main() { let visits: Vec<u32> = vec![12, 0, 7, 30]; let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` ist schon ein `u32` println!("{:?}", doubled);}Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Die ^^^^^^ zeigen in Zeile 3 auf *count, beschriftet mit „can’t be dereferenced“ (kann nicht dereferenziert werden). Die Überschrift sagt dir, was count wirklich ist: ein u32, kein &u32.
Verfolg die Typen entlang der Kette:
visits.iter()liefert dir Referenzen auf die Elemente:&u32,&u32, ….copied()macht aus jedem&u32eine einfache Kopie alsu32. Die Referenzen sind weg.- In
.map(|count| ...)istcountalso einu32, und*countverlangt von Rust, einem Zeiger zu folgen, den es nicht gibt.
Steht in der Überschrift type `{integer}` cannot be dereferenced, ist es dasselbe. {integer} ist die Schreibweise von rustc für „irgendein Ganzzahltyp, den ich noch nicht festgelegt habe“, meistens eine Zahl wie 72, der du nie einen Typ gegeben hast.
Das ist, als würdest du jemanden fragen „Was liegt an dieser Adresse?“ und ihm statt eines Zettels mit einer Adresse gleich das Paket geben. Er hat die Sache schon; es gibt keine Adresse, zu der er gehen könnte.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“In Rust sind eine Referenz (&T) und der Wert selbst (T) verschiedene Typen. * funktioniert nur mit Dingen, die irgendwohin zeigen: Referenzen &T und &mut T, Smart Pointer wie Box<T> und Rc<T> und jeder Typ, der den Trait Deref implementiert. Ein u32 oder ein einfaches Struct hat nichts davon, also hat * darauf keine Bedeutung.
Rust könnte das überflüssige * still ignorieren, tut es aber nicht. Ein überflüssiges * heißt meistens, dass du dich beim Typ irrst, und diese Verwirrung führt gern zu weiteren Bugs: Du vergleichst die falschen Dinge oder verschiebst einen Wert, den du eigentlich ausleihen wolltest. Deshalb hält rustc an und nennt dir den echten Typ. Siehe Borrowing und Smart Pointer.
Der umgekehrte Fehler hat einen eigenen Code. Vergisst du ein * bei einer Referenz, etwa count > 10, wobei count ein &u32 ist, bekommst du E0308, mismatched types (Typen passen nicht).
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Das * weglassen
Abschnitt betitelt „Lösung 1: Das * weglassen“Nimm diese Lösung fast immer, besonders nach .copied(), .cloned(), .into_iter() auf einem Vec oder allem anderen, was dir Werte liefert. Der Wert ist schon da, also benutz ihn einfach:
fn main() { let visits: Vec<u32> = vec![12, 0, 7, 30]; let doubled: Vec<u32> = visits.iter().copied().map(|count| count * 2).collect(); println!("{:?}", doubled);
// `filter` leiht dem Closure jedes Element, also IST `count` hier ein `&u32`, // und das `*` ist richtig. let busy: Vec<u32> = visits.iter().copied().filter(|count| *count > 10).collect(); println!("{:?}", busy);}Ausgabe:
[24, 0, 14, 60][12, 30]Der zweite Teil bringt viele Leute ins Stolpern: In derselben Kette bekommt map das Element selbst und filter eine Referenz auf das Element. Im Zweifel schau dir die Methode in der Doku an. filter nimmt FnMut(&Self::Item) -> bool, mit einem &. Siehe Iteratoren und Closures.
Lösung 2: In einer for-Schleife Werte oder Referenzen wählen
Abschnitt betitelt „Lösung 2: In einer for-Schleife Werte oder Referenzen wählen“Nimm diese Lösung, wenn das * in einer for-Schleife steht. for score in scores nimmt den Vec auseinander und gibt dir jeden Wert, also schlägt *score fehl:
error[E0614]: type `{integer}` cannot be dereferenced --> src/main.rs:5:18 |5 | total += *score; // ❌ `score` ist eine Zahl, keine Referenz | ^^^^^^ can't be dereferencedHier hat rustc den Typ noch nicht festgelegt, deshalb steht {integer} (irgendeine Ganzzahl) statt i32 in der Meldung.
Das fehlerhafte Programm:
fn main() { let scores = vec![72, 95, 88]; let mut total = 0; for score in scores { total += *score; // ❌ `score` ist eine Zahl, keine Referenz } println!("Summe: {}", total);}Lass entweder das * weg, oder lauf über &scores. Dann ist jedes score ein &i32, das * ist richtig, und du kannst den Vec nach der Schleife weiter benutzen:
fn main() { let scores = vec![72, 95, 88];
let mut total = 0; for score in &scores { total += *score; // `score` ist jetzt ein `&i32` } println!("Summe: {}", total);
// `scores` wurde nicht in die Schleife verschoben, ist also noch da. println!("{} Ergebnisse, Durchschnitt {}", scores.len(), total / scores.len() as i32);}Ausgabe:
Summe: 2553 Ergebnisse, Durchschnitt 85Eine schnelle Regel: for x in v liefert Werte, for x in &v liefert &-Referenzen, for x in &mut v liefert &mut-Referenzen. Nur die letzten beiden brauchen ein *. Siehe For-Schleifen und Vektoren.
Lösung 3: Die Referenz mit &x abgleichen oder *x benutzen, aber nicht beides
Abschnitt betitelt „Lösung 3: Die Referenz mit &x abgleichen oder *x benutzen, aber nicht beides“Nimm diese Lösung, wenn dein Closure oder deine Schleife schon ein & im Muster hat, etwa |&p|. Ein & in einem Muster packt die Referenz für dich aus, also ist p eine einfache Zahl, und *p ist ein Schritt zu viel:
error[E0614]: type `{integer}` cannot be dereferenced --> src/main.rs:3:53 |3 | let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` hat das `&` schon entfernt | ^^ can't be dereferencedDas fehlerhafte Programm:
fn main() { let prices = [3, 5, 8]; let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` hat das `&` schon entfernt println!("{:?}", with_fee);}Entscheide dich für einen Weg, die Referenz loszuwerden. Die beiden Zeilen unten tun dasselbe:
fn main() { let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| p + 1).collect(); // das Muster entfernt das `&` let same: Vec<i32> = prices.iter().map(|p| *p + 1).collect(); // `*` entfernt das `&` println!("{:?} {:?}", with_fee, same);
// `filter` auf `.iter()` bekommt `&&i32`: zwei `&`, also ist das Muster `&&p`. let pricey = prices.iter().filter(|&&p| p > 4).count(); println!("{} teure Artikel", pricey);}Ausgabe:
[4, 6, 9] [4, 6, 9]2 teure ArtikelDasselbe gilt für Schleifen: for &(name, qty) in &orders packt jede Referenz aus, also benutzt du name und qty ohne *. Siehe Pattern Matching.
Lösung 4: Den Typ prüfen, und bei Wrappern das Feld oder Deref benutzen
Abschnitt betitelt „Lösung 4: Den Typ prüfen, und bei Wrappern das Feld oder Deref benutzen“Nimm diese Lösung, wenn die Überschrift deinen eigenen Typ nennt, etwa type `Meters` cannot be dereferenced. Auch ein Struct ist keine Referenz, selbst wenn es nur einen einzigen Wert verpackt:
error[E0614]: type `Meters` cannot be dereferenced --> src/main.rs:5:18 |5 | let longer = *run + 1.0; // ❌ `run` ist ein `Meters`, keine Referenz | ^^^^ can't be dereferencedDas fehlerhafte Programm:
struct Meters(f64);
fn main() { let run = Meters(2.5); let longer = *run + 1.0; // ❌ `run` ist ein `Meters`, keine Referenz println!("{} m", longer);}An die Zahl in einem Tupel-Struct kommst du über sein Feld, .0:
struct Meters(f64);
fn main() { let run = Meters(2.5); let longer = run.0 + 1.0; println!("{} m", longer);}Ausgabe:
3.5 mIst dein Typ wirklich ein Wrapper wie ein Smart Pointer und soll * funktionieren, dann implementiere std::ops::Deref dafür. Mach das nur bei Wrapper-Typen; bei einem „Newtype“ wie Meters sind .0 oder eine Methode klarer. Du weißt nicht, welchen Typ eine Variable hat? Fahr in deinem Editor mit der Maus darüber (rust-analyzer zeigt den Typ an), oder vertrau der Überschrift: Sie nennt immer den echten Typ. Siehe Structs und Smart Pointer.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“* vor einem Struct-Feld. *config.retries, wobei config ein Struct ist (oder eine Referenz darauf) und retries ein u32, ergibt type `u32` cannot be dereferenced. Der . folgt der Referenz schon für dich. Lösung: config.retries.
Über eine HashMap als Wert iterieren. for (word, count) in counts { total += *count; } ergibt type `u32` cannot be dereferenced, weil eine Schleife über counts selbst dir Schlüssel und Werte als Eigentum gibt. Lösung: Lass das * weg, oder lauf über &counts, wenn du die Map danach noch brauchst. Siehe HashMap.
Nach .copied().max() oder .cloned().find(...). Diese liefern Option<u32>, nicht Option<&u32>, also ist in if let Some(best) = ... { *best } das * eins zu viel. Lösung: Benutz best direkt. Ohne .copied() liefert .iter().max() ein Option<&u32>, und dann ist *best richtig.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0308: mismatched types; der umgekehrte Fehler – ein fehlendes
*, wo eine Referenz auf einen einfachen Wert trifft. - E0369: binary operation cannot be applied to a type, ein weiterer Fehler, den du bekommen kannst, wenn sich Referenzen und Werte mischen.
- E0507: cannot move out of a reference; hier funktioniert
*zwar, würde aber einen Wert verschieben, der nichtCopyist. - E0610:
{integer}is a primitive type and has no fields, der „das ist nur eine Zahl“-Verwandte dieses Fehlers. - E0599: no method found, wenn der Wert nicht den Typ hat, den du dachtest.
- Alle Compilerfehler: die vollständige Liste der Fehlerseiten.
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Warum ergibt *count in visits.iter().copied().map(|count| *count + 1) den Fehler E0614?
2. for score in &scores { total += *score; }, wobei scores ein Vec<i32> ist. Kompiliert das?
3. prices.iter().map(|&p| *p * 2) ergibt E0614. Was ist eine korrekte Version?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0614 – Rust error codes index (auf Englisch): die offizielle Erklärung, mit einem minimalen Beispiel und der Lösung.
- Referenzen und Borrowing – Das Rust-Buch: was
&und*bedeuten und warum eine Referenz und ein Wert verschiedene Typen sind. - Intelligente Zeiger wie normale Referenzen behandeln – Das Rust-Buch: wie
*Referenzen folgt und wie der TraitDerefdas für deine eigenen Typen möglich macht. Iterator::copied– Doku der Standardbibliothek (auf Englisch): die Methode, die aus&T-ElementenT-Elemente macht – der häufigste Grund, warum ein*eins zu viel ist.- Destructuring pointers – Rust by Example (auf Englisch): der Unterschied zwischen
&valin einem Muster und*valin einem Ausdruck.