Aller au contenu

Erreur Rust E0614 : type cannot be dereferenced (déréférencement impossible)

E0614 veut dire : vous avez écrit * devant quelque chose qui n’est pas une référence, donc il n’y a rien à suivre. L’opérateur * veut dire « va à la valeur vers laquelle pointe cette référence ». Un simple u32, i32 ou une struct ne pointe nulle part : c’est la valeur. Ça arrive surtout dans les closures et les boucles, où l’on perd facilement de vue si l’on a un &u32 ou un u32. rustc vous donne le vrai type dans le titre de l’erreur, et la correction consiste presque toujours à supprimer un *. Cette page fait partie du guide des erreurs du compilateur Rust.

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` est déjà un `u32`
| ^^^^^^ can't be dereferenced

Le compilateur vous dit : « le type u32 ne peut pas être déréférencé ».

Voici le programme qui la provoque :

fn main() {
let visits: Vec<u32> = vec![12, 0, 7, 30];
let doubled: Vec<u32> = visits.iter().copied().map(|count| *count * 2).collect(); // ❌ `count` est déjà un `u32`
println!("{:?}", doubled);
}

Les ^^^^^^ pointent *count à la ligne 3, avec l’étiquette « can’t be dereferenced » (déréférencement impossible). Le titre vous dit ce qu’est vraiment count : un u32, pas un &u32.

Suivez les types le long de la chaîne :

  1. visits.iter() vous donne des références vers les éléments : &u32, &u32, …
  2. .copied() transforme chaque &u32 en une simple copie u32. Les références ont disparu.
  3. Dans .map(|count| ...), count est donc un u32, et *count demande à Rust de suivre un pointeur qui n’existe pas.

Quand le titre dit type `{integer}` cannot be dereferenced, c’est la même chose. {integer} est la façon dont rustc écrit « un type entier que je n’ai pas encore fixé », en général un nombre comme 72 auquel vous n’avez jamais donné de type.

C’est comme demander à quelqu’un « qu’y a-t-il à cette adresse ? » en lui tendant le colis au lieu d’un papier avec une adresse dessus. Il a déjà l’objet ; il n’y a aucune adresse où aller.

En Rust, une référence (&T) et la valeur elle-même (T) sont des types différents. * ne marche que sur ce qui pointe quelque part : les références &T et &mut T, les smart pointers (pointeurs intelligents) comme Box<T> et Rc<T>, et tout type qui implémente le trait Deref. Un u32 ou une struct ordinaire n’a rien de tout ça, donc * n’a aucun sens dessus.

Rust pourrait ignorer en silence le * en trop, mais il ne le fait pas. Un * en trop veut généralement dire que vous vous trompez sur le type que vous avez, et cette confusion a tendance à provoquer d’autres bugs : comparer les mauvaises choses, ou déplacer une valeur que vous vouliez emprunter. rustc s’arrête donc et vous dit le vrai type. Voir Le borrowing et Les smart pointers.

L’erreur inverse a son propre code. Si vous oubliez un * sur une référence, comme count > 10 où count est un &u32, vous obtenez E0308, types incompatibles.

Choisissez-la presque à chaque fois, surtout après .copied(), .cloned(), .into_iter() sur un Vec, ou tout ce qui vous donne des valeurs. La valeur est déjà là, utilisez-la directement :

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` prête chaque élément à la closure : ici, `count` EST un `&u32`
// et le `*` est correct.
let busy: Vec<u32> = visits.iter().copied().filter(|count| *count > 10).collect();
println!("{:?}", busy);
}

Sortie :

[24, 0, 14, 60]
[12, 30]
▶ Essayez par vous-même

Cette deuxième partie piège beaucoup de monde : dans la même chaîne, map reçoit l’élément lui-même et filter reçoit une référence vers l’élément. En cas de doute, regardez la méthode dans la documentation. filter prend un FnMut(&Self::Item) -> bool, avec un &. Voir Les itérateurs et Les closures.

Solution 2 : dans une boucle for, choisir entre valeurs et références

Section intitulée « Solution 2 : dans une boucle for, choisir entre valeurs et références »

Choisissez-la quand le * est dans une boucle for. for score in scores démonte le Vec et vous donne chaque valeur, donc *score échoue :

error[E0614]: type `{integer}` cannot be dereferenced
--> src/main.rs:5:18
|
5 | total += *score; // ❌ `score` est un nombre, pas une référence
| ^^^^^^ can't be dereferenced

Même message : cette fois, c’est un {integer} qui ne peut pas être déréférencé.

Le programme qui la provoque :

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in scores {
total += *score; // ❌ `score` est un nombre, pas une référence
}
println!("total : {}", total);
}

Soit vous retirez le *, soit vous parcourez &scores. Chaque score est alors un &i32, le * est correct, et vous pouvez encore utiliser le Vec après la boucle :

fn main() {
let scores = vec![72, 95, 88];
let mut total = 0;
for score in &scores {
total += *score; // `score` est maintenant un `&i32`
}
println!("total : {}", total);
// `scores` n'a pas été déplacé dans la boucle, il est toujours là.
println!("{} notes, moyenne {}", scores.len(), total / scores.len() as i32);
}

Sortie :

total : 255
3 notes, moyenne 85
▶ Essayez par vous-même

Une règle simple : for x in v donne des valeurs, for x in &v donne des références &, for x in &mut v donne des références &mut. Seuls les deux derniers ont besoin d’un *. Voir Les boucles for et Les vecteurs.

Solution 3 : déstructurer la référence avec &x, ou utiliser *x, mais pas les deux

Section intitulée « Solution 3 : déstructurer la référence avec &x, ou utiliser *x, mais pas les deux »

Choisissez-la quand votre closure ou votre boucle a déjà un & dans le motif (pattern), comme |&p|. Un & dans un motif déballe la référence pour vous : p est donc un simple nombre, et *p est une étape de trop :

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` a déjà retiré le `&`
| ^^ can't be dereferenced

Le programme qui la provoque :

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| *p + 1).collect(); // ❌ `&p` a déjà retiré le `&`
println!("{:?}", with_fee);
}

Choisissez une seule façon de vous débarrasser de la référence. Les deux lignes ci-dessous font la même chose :

fn main() {
let prices = [3, 5, 8];
let with_fee: Vec<i32> = prices.iter().map(|&p| p + 1).collect(); // le motif retire le `&`
let same: Vec<i32> = prices.iter().map(|p| *p + 1).collect(); // le `*` retire le `&`
println!("{:?} {:?}", with_fee, same);
// `filter` sur `.iter()` reçoit un `&&i32` : deux `&`, donc le motif est `&&p`.
let pricey = prices.iter().filter(|&&p| p > 4).count();
println!("{} articles chers", pricey);
}

Sortie :

[4, 6, 9] [4, 6, 9]
2 articles chers
▶ Essayez par vous-même

C’est pareil pour les boucles : for &(name, qty) in &orders déballe chaque référence, utilisez donc name et qty sans *. Voir Le pattern matching.

Solution 4 : vérifier le type, et utiliser le champ ou Deref pour les enveloppes

Section intitulée « Solution 4 : vérifier le type, et utiliser le champ ou Deref pour les enveloppes »

Choisissez-la quand le titre nomme votre propre type, comme type `Meters` cannot be dereferenced. Une struct n’est pas non plus une référence, même quand elle n’enveloppe qu’une seule valeur :

error[E0614]: type `Meters` cannot be dereferenced
--> src/main.rs:5:18
|
5 | let longer = *run + 1.0; // ❌ `run` est un `Meters`, pas une référence
| ^^^^ can't be dereferenced

Ici, c’est le type Meters qui ne peut pas être déréférencé.

Le programme qui la provoque :

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = *run + 1.0; // ❌ `run` est un `Meters`, pas une référence
println!("{} m", longer);
}

Pour obtenir le nombre à l’intérieur d’une struct tuple, utilisez son champ, .0 :

struct Meters(f64);
fn main() {
let run = Meters(2.5);
let longer = run.0 + 1.0;
println!("{} m", longer);
}

Sortie :

3.5 m
▶ Essayez par vous-même

Si votre type est vraiment une enveloppe du genre smart pointer et que vous voulez que * marche, implémentez std::ops::Deref pour lui. Ne le faites que pour des types enveloppes ; pour un « newtype » comme Meters, .0 ou une méthode est plus clair. Vous ne savez pas quel type a une variable ? Survolez-la dans votre éditeur (rust-analyzer affiche le type), ou faites confiance au titre de l’erreur : il nomme toujours le vrai type. Voir Les structs et Les smart pointers.

* sur un champ de struct. *config.retries, où config est une struct (ou une référence vers une struct) et retries un u32, donne type `u32` cannot be dereferenced. Le . suit déjà la référence pour vous. Correction : config.retries.

Parcourir une HashMap par valeur. for (word, count) in counts { total += *count; } donne type `u32` cannot be dereferenced, parce que parcourir counts lui-même donne des clés et des valeurs possédées. Correction : retirez le *, ou parcourez &counts si vous avez encore besoin de la map après. Voir Les HashMap.

Après .copied().max() ou .cloned().find(...). Ces appels donnent un Option<u32>, pas un Option<&u32>, donc dans if let Some(best) = ... { *best } le * est de trop. Correction : utilisez best directement. Sans .copied(), .iter().max() donne un Option<&u32> et *best est correct.

  • E0308 : types incompatibles ; l’erreur inverse, un * oublié là où une référence rencontre une simple valeur.
  • E0369 : opération binaire impossible sur un type, une autre erreur qu’on peut avoir en mélangeant références et valeurs.
  • E0507 : impossible de sortir une valeur d’une référence ; ici * marche, mais il déplacerait une valeur qui n’est pas Copy.
  • E0610 : {integer} est un type primitif et n’a pas de champs, le cousin « c’est juste un nombre » de cette erreur.
  • E0599 : aucune méthode trouvée, quand la valeur n’est pas du type que vous pensiez.
  • Toutes les erreurs du compilateur : la liste complète des pages d’erreurs.

Petit quiz

1. Dans visits.iter().copied().map(|count| *count + 1), pourquoi *count donne-t-il E0614 ?

2. for score in &scores { total += *score; } où scores est un Vec<i32>. Est-ce que ça compile ?

3. prices.iter().map(|&p| *p * 2) donne E0614. Quelle version est correcte ?

Score : 0 / 3