Ir al contenido

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.)

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 dereferenced

En 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);
}

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:

  1. visits.iter() te da referencias a los elementos: &u32, &u32, …
  2. .copied() convierte cada &u32 en una copia normal, un u32. Las referencias ya no están.
  3. Así que en .map(|count| ...), count es un u32, y *count le 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.

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.

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]
▶ Pruébalo tú mismo

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: 255
3 puntuaciones, promedio 85
▶ Pruébalo tú mismo

Una 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 dereferenced

El 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 caros
▶ Pruébalo tú mismo

Lo 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 dereferenced

El 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 m
▶ Pruébalo tú mismo

Si 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.

* 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.

  • 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 es Copy.
  • 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 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