Salta ai contenuti

Errore Rust E0610: primitive type doesn't have fields (campo su un numero)

E0610 significa: hai scritto something.field, ma something è un semplice numero (o un bool o un char), e questi non hanno nessun campo. Quasi sempre vuol dire che la variabile non è quello che pensi. Forse hai già tirato fuori il numero da una struct, una funzione ha restituito un numero invece di una struct, oppure hai scritto un .0 di troppo. Il messaggio ti dice il tipo esatto che vede Rust, quindi sei a un passo dalla soluzione. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)

error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields
--> src/main.rs:3:22
|
3 | println!("{}", x.value); // ❌ x is a number, it has no `value` field
| ^^^^^

Il compilatore ti dice: «{integer} è un tipo primitivo e quindi non ha campi».

Ecco il programma che lo provoca:

fn main() {
let x = 5;
println!("{}", x.value); // ❌ x is a number, it has no `value` field
}

(Il commento dice: x è un numero, non ha un campo value.)

Il tipo tra apici inversi è quello che Rust pensa sia la tua variabile. Qui è `{integer}`, che vuol dire «un numero intero, non ho ancora deciso di che tipo» (Rust sceglie i32 più tardi, se nient’altro decide). Vedrai anche `{float}` per i decimali, oppure un tipo concreto come u32, usize, f64, bool o char.

I ^^^^^ indicano il nome dopo il punto. Rust non sta dicendo «value è scritto male». Sta dicendo «un numero non può avere nessun campo, comunque lo chiami».

Quindi la domanda da farsi è: perché questa variabile è un numero? È come chiedere «il cartellino del prezzo del 5». Un prodotto ha un cartellino. Il numero 5 è solo un numero.

I tipi primitivi come i32, u32, f64, bool e char sono valori singoli integrati nel linguaggio. Non sono struct, quindi dentro non c’è niente da raggiungere con un punto e un nome. Vedi Tipi di dati.

Però hanno dei metodi: x.abs(), x.pow(2), price.round(), c.is_alphabetic(). I metodi si chiamano con (). I campi sono dati salvati dentro una struct, e li hanno solo struct, tuple e union.

Siccome Rust controlla ogni .campo in fase di compilazione, questa confusione non può mai diventare un crash o un undefined silenzioso a runtime. Lo scopri subito, alla riga esatta.

Scegli questa strada quando hai già tirato fuori il campo dalla struct prima. Dopo let count = counter.value;, count è il numero, quindi count.value chiede un campo su un u32:

error[E0610]: `u32` is a primitive type and therefore doesn't have fields
--> src/main.rs:8:26
|
8 | println!("{}", count.value);
| ^^^^^

Usa il numero così com’è, oppure torna alla struct e leggi il campo da lì:

struct Counter {
value: u32,
}
fn main() {
let mut counter = Counter { value: 0 };
counter.value += 3;
let count = counter.value; // ora count è un semplice u32
println!("{}", count); // ✅ usa il numero stesso
println!("{}", counter.value); // ✅ oppure leggi il campo dalla struct
}

Output:

3
3
▶ Provalo tu

Non sai che tipo ha una variabile? Passaci sopra con il mouse nel tuo editor (con rust-analyzer, vedi Strumenti Rust). Oppure scrivi per un momento let _: () = count;: rustc risponde con expected `()`, found `usize` e ti dice il tipo vero. Poi cancella la riga.

Soluzione 2: restituisci o salva la struct, non il numero

Sezione intitolata “Soluzione 2: restituisci o salva la struct, non il numero”

Scegli questa strada quando il valore arriva da una funzione o da una collezione, e ti aspettavi una struct. Due casi comuni:

  • Una funzione come fn find_order() -> u32 restituisce l’id di un ordine, e poi order.total fallisce perché order è un u32.
  • Una HashMap<&str, u32> salva solo i punteggi, e poi scores["ana"].score fallisce perché ogni valore è un u32, non un Player.

Decidi cosa vuoi davvero. Se ti servono più dati, cambia il tipo restituito o il tipo dei valori nella struct:

use std::collections::HashMap;
struct Order {
id: u32,
total: u32, // in centesimi
}
// restituisce l'intero Order, non solo un numero
fn 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!("L'ordine {} costa {} centesimi", order.id, order.total);
// la mappa salva interi Player, non solo i loro punteggi
let mut players: HashMap<&str, Player> = HashMap::new();
players.insert("ana", Player { score: 10, level: 2 });
let ana = &players["ana"];
println!("ana: punteggio {}, livello {}", ana.score, ana.level);
}

Output:

L'ordine 7 costa 1999 centesimi
ana: punteggio 10, livello 2
▶ Provalo tu

Se ti basta un numero, tieni il u32 e togli semplicemente la parte .campo. Vedi Struct e HashMap.

Scegli questa strada quando l’errore indica un .0 o un .1. Tuple e tuple struct usano posizioni per i loro campi, ed è facile scendere di un livello di troppo. Dopo let x = point.0;, x è già il numero, quindi x.0 dà `{integer}` is a primitive type. Lo stesso succede con un tipo «contenitore» come struct Meters(u32);: un .0 tira fuori l’u32, un secondo .0 fallisce.

struct Meters(u32);
fn main() {
let point = (3, 4);
let x = point.0; // x è già il numero 3
println!("x = {}", x); // non x.0
let m = Meters(42);
println!("{} m", m.0); // un .0 tira fuori l'u32 dalla tuple struct
let line = ((0, 0), (3, 4)); // tuple annidate: una posizione per livello
println!("y finale = {}", line.1.1);
}

Output:

x = 3
42 m
y finale = 4
▶ Provalo tu

Conta i livelli: ogni .0 o .1 scende di un livello dentro una tupla. Quando arrivi a un numero, fermati. Se le posizioni diventano confuse, dai loro un nome con una struct. Vedi Tuple.

Un metodo senza (). price.round su un f64, o x.abs su un i32, non è E0610 ma E0615, «attempted to take value of method», perché quei nomi sono metodi. Soluzione: price.round(), x.abs(). Una sorpresa: se il tipo è ancora {integer} (come in let x = -5;), anche x.abs dà E0610, e poi x.abs() dà E0689 «can’t call method abs on ambiguous numeric type {integer}». Scegli un tipo, let x: i32 = -5;, e x.abs() funziona.

Un riferimento a un numero. Se la variabile è un &u32 invece di un u32, il codice diventa E0609: no field `value` on type `&u32`. Un caso tipico è un ciclo come for (name, score) in &players, dove score è un &i32, e score.1 dà no field `1` on type `&{integer}`. Stessa causa, stesse soluzioni: score è già il numero.

Il risultato di len() o count(). let len = scores.len(); ti dà un usize, quindi len.count fallisce con `usize` is a primitive type. Soluzione: usa direttamente len.

Numeri con un’unità di misura. Se vuoi price.cents o distance.meters, crea una piccola struct: struct Price { cents: u64 }. Allora price.cents funziona, e il tipo ti impedisce di confondere i prezzi con altri numeri. Vedi Struct.

Verifica veloce

1. Dopo let total = cart.total; (dove total è un campo u32), cosa dà total.amount?

2. Cosa vuol dire {integer} nel messaggio?

3. let x = point.0; e poi x.0 dà E0610. Qual è la soluzione?

Punteggio: 0 / 3