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.)
El mensaje de error
Sección titulada «El mensaje de error»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}Qué significa
Sección titulada «Qué significa»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.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»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.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Usa el número directamente
Sección titulada «Solución 1: Usa el número directamente»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:
33¿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() -> u32devuelve el id de un pedido, y luegoorder.totalfalla porqueorderes unu32. - Un
HashMap<&str, u32>solo guarda puntuaciones, y luegoscores["ana"].scorefalla porque cada valor es unu32, no unPlayer.
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úmerofn 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 centavosana: puntuación 10, nivel 2Si solo necesitas un número, quédate con el u32 y quita la parte .campo. Mira Structs y HashMaps.
Solución 3: Quita el .0 que sobra
Sección titulada «Solución 3: Quita el .0 que sobra»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 = 342 my final = 4Cuenta 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.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»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.
Errores relacionados
Sección titulada «Errores relacionados»- E0609: no field
xon typeT: el tipo no tiene ningún campo con ese nombre. Es el que obtienes (y no E0610) con referencias como&u32. - E0615: attempted to take value of method: escribiste
price.rounden lugar deprice.round(). E0689: can't call method on ambiguous numeric type: un método sobre un número cuyo tipo todavía no se ha elegido. Añade un tipo comoi32.- E0599: no method named x found: la versión para métodos, por ejemplo un método que los números no tienen.
- E0308: mismatched types: aparece a menudo junto a E0610 cuando una función devuelve un número pero esperabas un struct.
- Todos los errores del compilador: la lista completa de páginas de errores.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»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
Para leer más
Sección titulada «Para leer más»- E0610 — Rust error codes index (en inglés): la explicación oficial de este error.
- Data Types — El libro de Rust (en inglés): los tipos escalares (enteros, decimales,
bool,char) y los compuestos (tuplas, arrays). También existe una traducción al español de la comunidad del libro. - Tuple Structs — El libro de Rust (en inglés): tipos envoltorio como
Meters(u32)y cómo funciona.0con ellos. - Primitives — Rust by Example (en inglés): los tipos incorporados, con ejemplos ejecutables.
i32— documentación de la biblioteca estándar (en inglés): todos los métodos que tiene un entero (y verás que todos se llaman con()).