Rust-Fehler E0610: primitive type doesn't have fields (Feld an einer Zahl)
E0610 bedeutet: Du hast something.field geschrieben, aber something ist eine einfache Zahl (oder ein bool oder char), und die haben überhaupt keine Felder. Fast immer heißt das: Die Variable ist nicht das, was du denkst. Vielleicht hast du die Zahl schon aus einem Struct herausgeholt, eine Funktion hat eine Zahl statt eines Structs zurückgegeben, oder du hast ein .0 zu viel geschrieben. Die Meldung nennt dir den genauen Typ, den Rust sieht. Damit bist du nur noch einen Schritt von der Lösung entfernt. (Diese Seite gehört zur Reihe Rust-Compilerfehler einfach erklärt.)
Die Fehlermeldung
Abschnitt betitelt „Die Fehlermeldung“error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> src/main.rs:3:22 |3 | println!("{}", x.value); // ❌ x ist eine Zahl, sie hat kein Feld `value` | ^^^^^Auf Deutsch: „{integer} ist ein primitiver Typ und hat deshalb keine Felder.“
Dieses Programm erzeugt den Fehler:
fn main() { let x = 5; println!("{}", x.value); // ❌ x ist eine Zahl, sie hat kein Feld `value`}Was sie bedeutet
Abschnitt betitelt „Was sie bedeutet“Der Typ in Backticks ist das, was Rust für deine Variable hält. Hier ist es `{integer}`. Das heißt: „irgendeine ganze Zahl, ich habe noch nicht entschieden, welche Sorte“ (Rust nimmt später i32, wenn nichts anderes entscheidet). Du siehst auch `{float}` für Kommazahlen, oder einen konkreten Typ wie u32, usize, f64, bool oder char.
Die ^^^^^ zeigen auf den Namen nach dem Punkt. Rust sagt damit nicht „value ist falsch geschrieben“. Es sagt: „Eine Zahl kann gar kein Feld haben, egal, wie du es nennst.“
Die Frage lautet also: Warum ist diese Variable eine Zahl? Das ist, als würdest du nach „dem Preisschild an der 5“ fragen. Ein Produkt hat ein Preisschild. Die Zahl 5 ist einfach nur eine Zahl.
Warum Rust das macht
Abschnitt betitelt „Warum Rust das macht“Primitive Typen wie i32, u32, f64, bool und char sind einzelne Werte, die fest in die Sprache eingebaut sind. Sie sind keine Structs, also gibt es in ihnen nichts, was du mit einem Punkt und einem Namen erreichen könntest. Siehe Datentypen.
Methoden haben sie aber schon: x.abs(), x.pow(2), price.round(), c.is_alphabetic(). Methoden rufst du mit () auf. Felder sind Daten, die in einem Struct gespeichert sind, und nur Structs, Tupel und Unions haben welche.
Weil Rust jedes .field beim Kompilieren prüft, kann diese Verwechslung nie zu einem Absturz oder einem stillen undefined zur Laufzeit werden. Du erfährst es sofort, in genau der richtigen Zeile.
So behebst du den Fehler
Abschnitt betitelt „So behebst du den Fehler“Lösung 1: Die Zahl direkt benutzen
Abschnitt betitelt „Lösung 1: Die Zahl direkt benutzen“Nimm diese Lösung, wenn du das Feld schon vorher aus dem Struct geholt hast. Nach let count = counter.value; ist count die Zahl, also fragt count.value nach einem Feld an einem u32:
error[E0610]: `u32` is a primitive type and therefore doesn't have fields --> src/main.rs:8:26 |8 | println!("{}", count.value); | ^^^^^Benutze entweder die Zahl so, wie sie ist, oder geh zurück zum Struct und lies das Feld dort:
struct Counter { value: u32,}
fn main() { let mut counter = Counter { value: 0 }; counter.value += 3;
let count = counter.value; // count ist jetzt ein einfacher u32 println!("{}", count); // ✅ die Zahl selbst benutzen println!("{}", counter.value); // ✅ oder das Feld aus dem Struct lesen}Ausgabe:
33Du weißt nicht, welchen Typ eine Variable hat? Fahr in deinem Editor mit der Maus darüber (mit rust-analyzer, siehe Rust-Werkzeuge). Oder schreib kurz let _: () = count;: rustc antwortet mit expected `()`, found `usize` („erwartet (), gefunden usize“) und verrät dir so den echten Typ. Lösch die Zeile danach wieder.
Lösung 2: Das Struct zurückgeben oder speichern, nicht die Zahl
Abschnitt betitelt „Lösung 2: Das Struct zurückgeben oder speichern, nicht die Zahl“Nimm diese Lösung, wenn der Wert aus einer Funktion oder einer Collection kommt und du ein Struct erwartet hast. Zwei häufige Fälle:
- Eine Funktion wie
fn find_order() -> u32gibt die ID einer Bestellung zurück, und dann scheitertorder.total, weilordereinu32ist. - Eine
HashMap<&str, u32>speichert nur Punktestände, und dann scheitertscores["ana"].score, weil jeder Wert einu32ist und keinPlayer.
Entscheide, was du wirklich willst. Brauchst du mehrere Daten, ändere den Rückgabetyp oder den Werttyp auf das Struct:
use std::collections::HashMap;
struct Order { id: u32, total: u32, // in Cent}
// gibt die ganze Order zurück, nicht nur eine Zahlfn new_order(id: u32, total: u32) -> Order { Order { id, total }}
struct Player { score: u32, level: u8,}
fn main() { let order = new_order(7, 1999); println!("Bestellung {} kostet {} Cent", order.id, order.total);
// die Map speichert ganze Player, nicht nur ihre Punkte let mut players: HashMap<&str, Player> = HashMap::new(); players.insert("ana", Player { score: 10, level: 2 });
let ana = &players["ana"]; println!("ana: Punkte {}, Level {}", ana.score, ana.level);}Ausgabe:
Bestellung 7 kostet 1999 Centana: Punkte 10, Level 2Brauchst du nur eine Zahl, behalte den u32 und lass einfach das .field weg. Siehe Structs und HashMaps.
Lösung 3: Das überzählige .0 entfernen
Abschnitt betitelt „Lösung 3: Das überzählige .0 entfernen“Nimm diese Lösung, wenn der Fehler auf ein .0 oder .1 zeigt. Tupel und Tupel-Structs benutzen Positionen für ihre Felder, und da geht man leicht eine Ebene zu tief. Nach let x = point.0; ist x schon die Zahl, also ergibt x.0 die Meldung `{integer}` is a primitive type. Dasselbe passiert bei einer Hülle wie struct Meters(u32);: Ein .0 holt den u32 heraus, ein zweites .0 scheitert.
struct Meters(u32);
fn main() { let point = (3, 4); let x = point.0; // x ist schon die Zahl 3 println!("x = {}", x); // nicht x.0
let m = Meters(42); println!("{} m", m.0); // ein .0 holt den u32 aus dem Tupel-Struct
let line = ((0, 0), (3, 4)); // verschachtelte Tupel: eine Position pro Ebene println!("Ende y = {}", line.1.1);}Ausgabe:
x = 342 mEnde y = 4Zähl die Ebenen: Jedes .0 oder .1 geht eine Ebene tiefer in ein Tupel. Bist du bei einer Zahl angekommen, hör auf. Werden die Positionen unübersichtlich, gib ihnen mit einem Struct lieber Namen. Siehe Per Position auf Elemente zugreifen und Tupel oder Struct?.
Wo du ihn oft siehst
Abschnitt betitelt „Wo du ihn oft siehst“Eine Methode ohne (). price.round an einem f64 oder x.abs an einem i32 ist nicht E0610, sondern E0615, „attempted to take value of method“ (Versuch, den Wert einer Methode zu nehmen), weil diese Namen wirklich Methoden sind. Lösung: price.round(), x.abs(). Eine Überraschung gibt es: Ist der Typ noch {integer} (wie bei let x = -5;), ergibt sogar x.abs den Fehler E0610, und x.abs() ergibt dann E0689 „can’t call method abs on ambiguous numeric type {integer}“ (Methode kann auf einem mehrdeutigen Zahlentyp nicht aufgerufen werden). Leg einen Typ fest, let x: i32 = -5;, und x.abs() funktioniert.
Eine Referenz auf eine Zahl. Ist die Variable ein &u32 statt eines u32, wechselt der Code zu E0609: no field `value` on type `&u32`. Typisch ist eine Schleife wie for (name, score) in &players, in der score ein &i32 ist und score.1 die Meldung no field `1` on type `&{integer}` ergibt. Gleiche Ursache, gleiche Lösungen: score ist schon die Zahl.
Das Ergebnis von len() oder count(). let len = scores.len(); gibt dir einen usize, also scheitert len.count mit `usize` is a primitive type. Lösung: Benutze len direkt.
Zahlen mit einer Einheit. Willst du price.cents oder distance.meters, bau ein kleines Struct: struct Price { cents: u64 }. Dann funktioniert price.cents, und der Typ verhindert, dass du Preise mit anderen Zahlen verwechselst. Siehe Structs.
Verwandte Fehler
Abschnitt betitelt „Verwandte Fehler“- E0609: no field
xon typeT: Der Typ hat kein Feld mit diesem Namen. Diesen Fehler (nicht E0610) bekommst du bei Referenzen wie&u32. - E0615: attempted to take value of method: Du hast
price.roundstattprice.round()geschrieben. E0689: can't call method on ambiguous numeric type: eine Methode an einer Zahl, deren Typ noch nicht feststeht. Gib einen Typ wiei32an.- E0599: no method named x found: die Methoden-Version, zum Beispiel eine Methode, die Zahlen nicht haben.
- E0308: mismatched types: erscheint oft neben E0610, wenn eine Funktion eine Zahl zurückgibt, du aber ein Struct erwartet hast.
- Alle Compilerfehler einfach erklärt
Kurzer Check
Abschnitt betitelt „Kurzer Check“Kurzer Check
1. Was ergibt total.amount nach let total = cart.total; (wobei total ein Feld vom Typ u32 ist)?
2. Was bedeutet {integer} in der Meldung?
3. let x = point.0; und danach x.0 ergibt E0610. Was ist die Lösung?
Punkte: 0 / 3
Weiterlesen
Abschnitt betitelt „Weiterlesen“- E0610 – Rust error codes index (auf Englisch): die offizielle Erklärung dieses Fehlers.
- Datentypen – Das Rust-Buch: skalare Typen (ganze Zahlen, Gleitkommazahlen,
bool,char) und zusammengesetzte Typen (Tupel, Arrays). - Mit Tupel-Strukturen verschiedene Typen erzeugen – Das Rust-Buch: Hüllentypen wie
Meters(u32)und wie.0bei ihnen funktioniert. - Primitives – Rust by Example (auf Englisch): die eingebauten Typen, mit ausführbaren Beispielen.
i32– Doku der Standardbibliothek (auf Englisch): jede Methode, die eine ganze Zahl hat (und du wirst sehen: Alle werden mit()aufgerufen).