Error E0614 de Rust: type cannot be dereferenced (no es una referencia)
E0614 significa: escribiste * delante de algo que no es una referencia, así que no hay nada a lo que seguir. El operador * significa “ve al valor al que apunta esta referencia”. Un u32, un i32 o un struct normal no apunta a ningún sitio: es el valor. Suele pasar en closures y bucles, donde es fácil perder la cuenta de si tienes un &u32 o un u32. rustc te dice el tipo real en el titular, y la solución casi siempre es borrar un *. (Esta página forma parte de Errores del compilador de Rust explicados.)
El mensaje de error
Sección titulada «El mensaje de error»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` is already a `u32` | ^^^^^^ can't be dereferencedEn español: “el tipo u32 no se puede desreferenciar”. Es decir, no se le puede aplicar *.
Este es el programa que lo produce:
fn main() { let visits: Vec<u32> = vec![12, 0, 7, 30]; let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` is already a `u32` println!("{:?}", doubled);}Qué significa
Sección titulada «Qué significa»El ^^^^^^ señala *count en la línea 3, con la etiqueta “can’t be dereferenced” (no se puede desreferenciar). El titular te dice qué es count en realidad: un u32, no un &u32.
Sigue los tipos a lo largo de la cadena:
visits.iter()te da referencias a los elementos:&u32,&u32, ….copied()convierte cada&u32en una copia normal, unu32. Las referencias ya no están.- Así que en
.map(|count| ...),countes unu32, y*countle pide a Rust que siga un puntero que no existe.
Cuando el titular dice type `{integer}` cannot be dereferenced, es lo mismo. {integer} es la forma en que rustc escribe “algún tipo entero que todavía no he decidido”, normalmente un número como 72 al que nunca le diste un tipo.
Es como preguntarle a alguien “¿qué hay en esta dirección?” y darle el paquete en lugar de un papelito con la dirección. Ya tiene la cosa; no hay ninguna dirección a la que ir.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»En Rust, una referencia (&T) y el propio valor (T) son tipos distintos. * solo funciona con cosas que apuntan a algún sitio: las referencias &T y &mut T, los smart pointers como Box<T> y Rc<T>, y cualquier tipo que implemente el trait Deref. Un u32 o un struct normal no tiene nada de eso, así que * sobre él no tiene sentido.
Rust podría ignorar en silencio el * de más, pero no lo hace. Un * de más suele significar que te equivocas sobre qué tipo tienes, y esa confusión tiende a causar otros bugs: comparar las cosas equivocadas, o mover un valor que querías tomar prestado. Por eso rustc se detiene y te dice el tipo real. Mira Borrowing y Punteros inteligentes.
El error contrario tiene su propio código. Si olvidas un * en una referencia, como count > 10 cuando count es un &u32, te sale E0308, tipos que no coinciden.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Quita el *
Sección titulada «Solución 1: Quita el *»Elige esta casi siempre, sobre todo después de .copied(), .cloned(), .into_iter() sobre un Vec o cualquier otra cosa que te entregue valores. El valor ya está ahí, así que úsalo sin más:
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` le presta cada elemento a la closure, así que aquí `count` SÍ es un `&u32` // y el `*` es correcto. let busy: Vec<u32> = visits.iter().copied().filter(|count| *count > 10).collect(); println!("{:?}", busy);}Salida:
[24, 0, 14, 60][12, 30]Esa segunda parte confunde a mucha gente: en la misma cadena, map recibe el elemento en sí y filter recibe una referencia al elemento. Si tienes dudas, mira el método en la documentación. filter recibe FnMut(&Self::Item) -> bool, con un &. Mira Iteradores y Closures.
Solución 2: En un bucle for, elige valores o referencias
Sección titulada «Solución 2: En un bucle for, elige valores o referencias»Elige esta cuando el * está dentro de un bucle for. for score in scores desarma el Vec y te da cada valor, así que *score falla:
error[E0614]: type `{integer}` cannot be dereferenced --> src/main.rs:5:18 |5 | total += *score; // ❌ `score` is a number, not a reference | ^^^^^^ can't be dereferenced“El tipo {integer} no se puede desreferenciar”. El programa con el error:
fn main() { let scores = vec![72, 95, 88]; let mut total = 0; for score in scores { total += *score; // ❌ `score` is a number, not a reference } println!("total: {}", total);}O quitas el *, o recorres &scores. Así cada score es un &i32, el * es correcto y puedes seguir usando el Vec después del bucle:
fn main() { let scores = vec![72, 95, 88];
let mut total = 0; for score in &scores { total += *score; // ahora `score` es un `&i32` } println!("total: {}", total);
// `scores` no se movió al bucle, así que sigue aquí. println!("{} puntuaciones, promedio {}", scores.len(), total / scores.len() as i32);}Salida:
total: 2553 puntuaciones, promedio 85Una regla rápida: for x in v da valores, for x in &v da referencias &, y for x in &mut v da referencias &mut. Solo las dos últimas necesitan un *. Mira Bucles for y Vectores.
Solución 3: Haz match con la referencia usando &x, o usa *x, pero no las dos cosas
Sección titulada «Solución 3: Haz match con la referencia usando &x, o usa *x, pero no las dos cosas»Elige esta cuando tu closure o tu bucle ya tiene un & en el patrón, como |&p|. Un & en un patrón desempaqueta la referencia por ti, así que p es un número normal y *p es un paso de más:
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` already removed the `&` | ^^ can't be dereferencedEl programa con el error:
fn main() { let prices = [3, 5, 8]; let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` already removed the `&` println!("{:?}", with_fee);}Elige una sola forma de quitarte la referencia de encima. Las dos líneas de abajo hacen lo mismo:
fn main() { let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| p + 1).collect(); // el patrón quita el `&` let same: Vec<i32> = prices.iter().map(|p| *p + 1).collect(); // el `*` quita el `&` println!("{:?} {:?}", with_fee, same);
// `filter` sobre `.iter()` recibe `&&i32`: dos `&`, así que el patrón es `&&p`. let pricey = prices.iter().filter(|&&p| p > 4).count(); println!("{} productos caros", pricey);}Salida:
[4, 6, 9] [4, 6, 9]2 productos carosLo mismo vale para los bucles: for &(name, qty) in &orders desempaqueta cada referencia, así que usa name y qty sin *. Mira Coincidencia de patrones.
Solución 4: Revisa el tipo, y usa el campo o Deref en los envoltorios
Sección titulada «Solución 4: Revisa el tipo, y usa el campo o Deref en los envoltorios»Elige esta cuando el titular nombra tu propio tipo, como type `Meters` cannot be dereferenced. Un struct tampoco es una referencia, aunque solo envuelva un valor:
error[E0614]: type `Meters` cannot be dereferenced --> src/main.rs:5:18 |5 | let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference | ^^^^ can't be dereferencedEl programa con el error:
struct Meters(f64);
fn main() { let run = Meters(2.5); let longer = *run + 1.0; // ❌ `run` is a `Meters`, not a reference println!("{} m", longer);}Para sacar el número de dentro de un tuple struct, usa su campo, .0:
struct Meters(f64);
fn main() { let run = Meters(2.5); let longer = run.0 + 1.0; println!("{} m", longer);}Salida:
3.5 mSi tu tipo de verdad es un envoltorio parecido a un smart pointer y quieres que * funcione, implementa std::ops::Deref para él. Hazlo solo en tipos envoltorio; para un “newtype” como Meters, .0 o un método es más claro. ¿No sabes qué tipo tiene una variable? Pasa el ratón por encima en tu editor (rust-analyzer te muestra el tipo), o fíate del titular: siempre nombra el tipo real. Mira Structs y Punteros inteligentes.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»* sobre el campo de un struct. *config.retries, donde config es un struct (o una referencia a uno) y retries es un u32, da type `u32` cannot be dereferenced. El . ya sigue la referencia por ti. Solución: config.retries.
Recorrer un HashMap por valor. for (word, count) in counts { total += *count; } da type `u32` cannot be dereferenced, porque recorrer counts directamente te da claves y valores en propiedad. Solución: quita el *, o recorre &counts si necesitas el mapa después. Mira HashMaps.
Después de .copied().max() o .cloned().find(...). Estos dan Option<u32>, no Option<&u32>, así que en if let Some(best) = ... { *best } el * sobra. Solución: usa best directamente. Sin .copied(), .iter().max() da Option<&u32> y *best es correcto.
Errores relacionados
Sección titulada «Errores relacionados»- E0308: tipos que no coinciden; el error contrario, un
*que falta donde una referencia se encuentra con un valor normal. - E0369: una operación binaria no se puede aplicar a un tipo, otro error que puede salir cuando se mezclan referencias y valores.
- E0507: no se puede mover fuera de una referencia; aquí
*sí funciona, pero movería un valor que no esCopy. - E0610:
{integer}es un tipo primitivo y no tiene campos, el primo “es solo un número” de este error. - E0599: no se encontró el método, cuando el valor no es del tipo que creías.
- 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. En visits.iter().copied().map(|count| *count + 1), ¿por qué *count da E0614?
2. for score in &scores { total += *score; } con scores de tipo Vec<i32>. ¿Compila?
3. prices.iter().map(|&p| *p * 2) da E0614. ¿Cuál es una versión correcta?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0614 — Rust error codes index (en inglés): la explicación oficial, con un ejemplo mínimo y la solución.
- References and Borrowing — El libro de Rust (en inglés): qué significan
&y*, y por qué una referencia y un valor son tipos distintos. También existe una traducción al español de la comunidad del libro. - Treating Smart Pointers Like Regular References — El libro de Rust (en inglés): cómo sigue
*las referencias, y cómo el traitDerefhace que funcione con tus propios tipos. Iterator::copied— documentación de la biblioteca estándar (en inglés): el método que convierte elementos&Ten elementosT, la razón más común de que un*sobre.- Destructuring pointers — Rust by Example (en inglés): la diferencia entre
&valen un patrón y*valen una expresión.