Ir al contenido

Error E0610 de Rust: primitive type doesn't have fields (campo en un número)

E0610 significa: escribiste algo.campo, pero algo es un número sin más (o un bool o un char), y esos tipos no tienen ningún campo. Casi siempre quiere decir que la variable no es lo que crees. Quizá ya sacaste el número de un struct, una función devolvió un número en lugar de un struct, o escribiste un .0 de más. El mensaje te dice el tipo exacto que ve Rust, así que estás a un paso de la solución. (Esta página forma parte de Errores del compilador de Rust explicados.)

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
| ^^^^^

El mensaje quiere decir “{integer} es un tipo primitivo y, por lo tanto, no tiene campos”.

Este es el programa que lo produce:

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

El tipo entre comillas invertidas es lo que Rust cree que es tu variable. Aquí es `{integer}`, que significa “algún número entero, todavía no he decidido de qué clase” (Rust elige i32 más tarde si nada más lo decide). También verás `{float}` para números decimales, o un tipo concreto como u32, usize, f64, bool o char.

Los ^^^^^ señalan el nombre que va después del punto. Rust no te está diciendo “value está mal escrito”. Te está diciendo “un número no puede tener ningún campo, lo llames como lo llames”.

Así que la pregunta que debes hacerte es: ¿por qué esta variable es un número? Es como pedir “la etiqueta del precio del 5”. Un producto tiene una etiqueta con el precio. El número 5 es solo un número.

Los tipos primitivos como i32, u32, f64, bool y char son valores simples que vienen incorporados en el lenguaje. No son structs, así que no hay nada dentro de ellos a lo que llegar con un punto y un nombre. Mira Tipos de datos.

Eso sí, tienen métodos: x.abs(), x.pow(2), price.round(), c.is_alphabetic(). Los métodos se llaman con (). Los campos son datos guardados dentro de un struct, y solo los structs, las tuplas y las uniones los tienen.

Como Rust comprueba cada .campo al compilar, esta confusión nunca puede convertirse en un fallo o en un undefined silencioso mientras el programa se ejecuta. Te enteras enseguida, en la línea exacta.

Elige esta cuando ya sacaste el campo del struct antes. Después de let count = counter.value;, count es el número, así que count.value pide un campo a 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 el número tal cual, o vuelve al struct y lee el campo desde ahí:

struct Counter {
value: u32,
}
fn main() {
let mut counter = Counter { value: 0 };
counter.value += 3;
let count = counter.value; // ahora count es un simple u32
println!("{}", count); // ✅ usa el número tal cual
println!("{}", counter.value); // ✅ o lee el campo del struct
}

Salida:

3
3
▶ Pruébalo tú mismo

¿No sabes de qué tipo es una variable? Pasa el ratón por encima en tu editor (con rust-analyzer, mira Herramientas de Rust). O escribe let _: () = count; por un momento: rustc responde con expected `()`, found `usize` (se esperaba (), se encontró usize) y te dice el tipo real. Después borra la línea.

Solución 2: Devuelve o guarda el struct, no el número

Sección titulada «Solución 2: Devuelve o guarda el struct, no el número»

Elige esta cuando el valor viene de una función o de una colección, y esperabas un struct. Dos casos habituales:

  • Una función como fn find_order() -> u32 devuelve el id de un pedido, y luego order.total falla porque order es un u32.
  • Un HashMap<&str, u32> solo guarda puntuaciones, y luego scores["ana"].score falla porque cada valor es un u32, no un Player.

Decide qué quieres de verdad. Si necesitas varios datos, cambia el tipo de retorno o el tipo de los valores al struct:

use std::collections::HashMap;
struct Order {
id: u32,
total: u32, // en centavos
}
// devuelve el Order completo, no solo un número
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!("El pedido {} cuesta {} centavos", order.id, order.total);
// el mapa guarda Players completos, no solo sus puntuaciones
let mut players: HashMap<&str, Player> = HashMap::new();
players.insert("ana", Player { score: 10, level: 2 });
let ana = &players["ana"];
println!("ana: puntuación {}, nivel {}", ana.score, ana.level);
}

Salida:

El pedido 7 cuesta 1999 centavos
ana: puntuación 10, nivel 2
▶ Pruébalo tú mismo

Si solo necesitas un número, quédate con el u32 y quita la parte .campo. Mira Structs y HashMaps.

Elige esta cuando el error señala un .0 o un .1. Las tuplas y los tuple structs usan posiciones para sus campos, y es fácil bajar un nivel de más. Después de let x = point.0;, x ya es el número, así que x.0 da `{integer}` is a primitive type. Lo mismo pasa con un envoltorio como struct Meters(u32);: un .0 saca el u32, y un segundo .0 falla.

struct Meters(u32);
fn main() {
let point = (3, 4);
let x = point.0; // x ya es el número 3
println!("x = {}", x); // no x.0
let m = Meters(42);
println!("{} m", m.0); // un .0 saca el u32 del tuple struct
let line = ((0, 0), (3, 4)); // tuplas anidadas: una posición por nivel
println!("y final = {}", line.1.1);
}

Salida:

x = 3
42 m
y final = 4
▶ Pruébalo tú mismo

Cuenta los niveles: cada .0 o .1 entra un nivel en una tupla. Cuando llegas a un número, para. Si las posiciones se vuelven confusas, ponles nombre usando un struct. Mira Acceder a los elementos por posición y Cuándo usar una tupla y cuándo un struct.

Un método sin (). price.round sobre un f64, o x.abs sobre un i32, no da E0610 sino E0615, “attempted to take value of method” (intentaste tomar el valor de un método), porque esos nombres son métodos. Solución: price.round(), x.abs(). Una sorpresa: si el tipo todavía es {integer} (como en let x = -5;), incluso x.abs da E0610, y x.abs() da entonces E0689 “can’t call method abs on ambiguous numeric type {integer}” (no se puede llamar al método abs sobre un tipo numérico ambiguo). Elige un tipo, let x: i32 = -5;, y x.abs() funciona.

Una referencia a un número. Si la variable es un &u32 en lugar de un u32, el código cambia a E0609: no field `value` on type `&u32`. Un sitio habitual es un bucle como for (name, score) in &players, donde score es un &i32, y score.1 da no field `1` on type `&{integer}`. La causa es la misma y las soluciones también: score ya es el número.

El resultado de len() o count(). let len = scores.len(); te da un usize, así que len.count falla con `usize` is a primitive type. Solución: usa len directamente.

Números con unidad. Si quieres price.cents o distance.meters, crea un struct pequeño: struct Price { cents: u64 }. Así price.cents funciona, y el tipo evita que confundas precios con otros números. Mira Structs.

Comprueba lo aprendido

1. Después de let total = cart.total; (donde total es un campo u32), ¿qué da total.amount?

2. ¿Qué significa {integer} en el mensaje?

3. let x = point.0; y después x.0 da E0610. ¿Cuál es la solución?

Puntuación: 0 / 3