Erreur Rust E0412 : cannot find type in this scope (type introuvable)
E0412 veut dire que vous avez écrit un nom de type que Rust ne voit pas depuis cet endroit, par exemple dans la signature d’une fonction comme fn print_invoice(inv: &Invoce). C’est une erreur très courante, et facile à corriger : une faute de frappe, une ligne use qui manque, ou un générique <T> que vous avez oublié de déclarer. Une chose risque de vous dérouter au début : depuis Rust 1.93, le compilateur affiche cette erreur sous le code E0425, avec le même message, cannot find type. Cette page couvre les deux, et elle fait partie du guide des erreurs du compilateur Rust.
Le message d’erreur
Section intitulée « Le message d’erreur »Voici ce qu’affichent Rust 1.93 et les versions plus récentes (le compilateur actuel est la 1.97) :
error[E0425]: cannot find type `Invoce` in this scope --> src/main.rs:2:24 |1 | struct Invoice { total: u32 } | -------------- similarly named struct `Invoice` defined here2 | fn print_invoice(inv: &Invoce) { // ❌ faute de frappe : Invoce | ^^^^^^ |help: a struct with a similar name exists |2 | fn print_invoice(inv: &Invoice) { // ❌ faute de frappe : Invoce | +Et voici le même programme avec Rust 1.92 ou plus ancien, la version utilisée par la plupart des articles de blog et des réponses sur Stack Overflow :
error[E0412]: cannot find type `Invoce` in this scope --> src/main.rs:2:24 |1 | struct Invoice { total: u32 } | -------------- similarly named struct `Invoice` defined here2 | fn print_invoice(inv: &Invoce) { | ^^^^^^ help: a struct with a similar name exists: `Invoice`Dans les deux cas, le compilateur vous dit : « impossible de trouver le type Invoce dans cette portée ». L’étiquette « similarly named struct Invoice defined here » montre une struct au nom proche, et l’aide « a struct with a similar name exists » vous propose ce nom.
Voici le programme qui provoque les deux :
struct Invoice { total: u32 }fn print_invoice(inv: &Invoce) { // ❌ faute de frappe : Invoce println!("{}", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}La page officielle de E0412 (en anglais) commence maintenant par « this error code is no longer emitted by the compiler » (ce code d’erreur n’est plus émis par le compilateur). Le problème n’a pas disparu : il est simplement passé sous E0425, qui couvre aussi les variables et les fonctions introuvables. Tout ce qui suit fonctionne de la même façon pour les deux codes.
Ce que ça veut dire
Section intitulée « Ce que ça veut dire »Les ^^^^^^ pointent Invoce dans la signature. Pour vérifier cette fonction, Rust doit savoir ce qu’est un Invoce : quelle place il prend, quels champs il possède. Il a regardé tous les types visibles depuis la ligne 2 (vos propres structs et enums, vos lignes use et le prelude) et n’a rien trouvé avec ce nom.
La ligne help: vous dit dans quelle situation vous êtes :
- « a struct with a similar name exists » (une struct au nom proche existe) : une faute de frappe. Le
+montre la lettre qui manque. - « consider importing this struct » (pensez à importer cette struct) : le type existe ailleurs, et il vous faut une ligne
use. - « you might be missing a type parameter » (il vous manque peut-être un paramètre de type) : vous avez utilisé un générique
Tsans déclarer<T>. - aucune aide : le type n’existe pas encore. Vous ne l’avez pas écrit, ou il se trouve dans un fichier que Rust ne connaît pas.
C’est comme une recette qui dit « ajoutez 200 g d’Invoce ». Le cuisinier sait ce que sont la farine et le sucre, mais pas l’« Invoce » : il s’arrête avant même de commencer.
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »Rust vérifie la signature de chaque fonction avant que le programme ne s’exécute. Chaque type de paramètre et de retour doit désigner un type réel et connu, car Rust s’en sert pour savoir combien de mémoire la valeur occupe et quels méthodes et champs elle possède. Un nom qu’il ne trouve pas, Rust refuse de le deviner.
Seul un petit ensemble de noms de types est visible partout sans use : le prelude, avec String, Vec, Option, Result, Box et quelques autres. Tout le reste a besoin soit de votre propre définition, soit d’une ligne use, soit d’un chemin complet comme std::num::ParseIntError. Voir Les modules pour comprendre les chemins et use.
Pourquoi le code a-t-il changé ? Depuis Rust 1.93, rustc signale un type introuvable sous E0425, le code qu’il utilisait déjà pour une variable ou une fonction introuvable. Le message dit toujours type, vous savez donc toujours quelle sorte de nom manque.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : corriger l’orthographe, ou définir le type
Section intitulée « Solution 1 : corriger l’orthographe, ou définir le type »Choisissez-la quand rustc dit qu’un nom proche existe, ou ne donne aucune aide. Les noms de types sont sensibles à la casse : invoice, Invoce et Invoice sont trois noms différents. S’il n’y a aucun nom proche, écrivez d’abord la struct ou l’enum :
struct Invoice { total: u32,}
fn print_invoice(inv: &Invoice) { println!("Total de la facture : {} EUR", inv.total);}
fn main() { print_invoice(&Invoice { total: 120 });}Sortie :
Total de la facture : 120 EURSolution 2 : ajouter la ligne use que propose rustc
Section intitulée « Solution 2 : ajouter la ligne use que propose rustc »Choisissez-la quand l’aide dit consider importing this struct (ou enum, ou alias de type). Les types de la bibliothèque standard qui ne sont pas dans le prelude, comme HashMap, ParseIntError ou Ordering, ont besoin d’une ligne use. Ici, une fonction renvoie une erreur d’analyse (parse) :
error[E0425]: cannot find type `ParseIntError` in this scope --> src/main.rs:1:40 |1 | fn parse_age(text: &str) -> Result<u8, ParseIntError> { | ^^^^^^^^^^^^^ not found in this scope |help: consider importing this struct |1 + use std::num::ParseIntError; |L’étiquette « not found in this scope » veut dire « introuvable dans cette portée ». Copiez la ligne proposée en haut du fichier :
use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> { text.trim().parse()}
fn main() { println!("{:?}", parse_age(" 42 ")); println!("{:?}", parse_age("quarante").is_err());}Sortie :
Ok(42)trueSi vous avez écrit HashMap::new() (un chemin avec ::) plutôt qu’un type dans une signature, l’erreur est E0433, et la même ligne use la corrige. Si rustc propose plusieurs imports, lisez-les avant de choisir : ce sont des types différents qui portent le même nom.
Solution 3 : déclarer le paramètre de type générique
Section intitulée « Solution 3 : déclarer le paramètre de type générique »Choisissez-la quand l’aide dit you might be missing a type parameter. En Rust, T n’est pas un mot spécial. C’est un nom que vous inventez, et vous devez l’annoncer entre chevrons après le nom de la fonction. Sans <T>, Rust cherche un vrai type appelé T :
error[E0425]: cannot find type `T` in this scope --> src/main.rs:1:21 |1 | fn largest(items: &[T]) -> &T { | ^ not found in this scope |help: you might be missing a type parameter |1 | fn largest<T>(items: &[T]) -> &T { | +++Vous obtenez la même erreur une fois pour chaque endroit où T apparaît. Ajoutez <T>, plus les traits dont la fonction a besoin. Pour comparer des éléments avec >, T doit implémenter PartialOrd :
fn largest<T: PartialOrd>(items: &[T]) -> &T { let mut best = &items[0]; for item in items { if item > best { best = item; } } best}
fn main() { println!("{}", largest(&[34, 50, 25, 100, 65])); println!("{}", largest(&['y', 'm', 'a', 'q']));}Sortie :
100yC’est pareil pour les structs : struct Wrapper { items: Vec<Item> } échoue, sauf si vous écrivez struct Wrapper<Item> ou définissez un vrai type Item. Si vous oubliez : PartialOrd, vous obtenez à la place E0369 sur le >. Voir Une fonction générique.
Solution 4 : importer un type depuis un autre module
Section intitulée « Solution 4 : importer un type depuis un autre module »Choisissez-la quand le type est à vous, mais se trouve dans un autre module. Une surprise fréquente : un module à l’intérieur de votre fichier ne voit pas non plus les types définis en haut du fichier. Chaque module a sa propre portée :
error[E0425]: cannot find type `Order` in this scope --> src/main.rs:7:26 |7 | pub fn print(order: &Order) -> String { | ^^^^^ not found in this scope |help: consider importing this struct |7 + use crate::Order; |Le 7 + veut dire « ajoutez cette ligne dans le module, à la ligne 7 ». crate::Order est le chemin depuis la racine de votre crate ; super::Order (« depuis le module parent ») marche aussi :
struct Order { id: u32, total: u32,}
mod receipts { use crate::Order;
pub fn print(order: &Order) -> String { format!("Commande n°{} : {} EUR", order.id, order.total) }}
fn main() { let order = Order { id: 7, total: 42 }; println!("{}", receipts::print(&order));}Sortie :
Commande n°7 : 42 EURDans l’autre sens, c’est pareil : un type défini dans mod shop doit être déclaré pub struct Product, et main a besoin de use crate::shop::Product; (ou du chemin complet shop::Product) pour le nommer. Vous rencontrerez surtout ce cas dans mod tests, où use super::*; en haut du module importe tout ce que contient le module parent.
Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »Un type venant d’un fichier que vous n’avez pas déclaré. fn save(user: models::User) avec un fichier src/models.rs mais sans ligne mod models; ne donne ni E0412 ni E0425, mais E0433 : cannot find module or crate `models` in this scope (module ou crate models introuvable). Correction : ajoutez mod models; en haut de main.rs, et rendez la struct pub.
Self en dehors d’un impl. fn new_counter() -> Self au niveau principal du fichier donne son propre code, E0411 : cannot find type `Self` in this scope, avec l’étiquette `Self` is only available in impls, traits, and type definitions (Self n’existe que dans les impl, les traits et les définitions de types). Correction : déplacez la fonction dans impl Counter { ... }, ou écrivez Counter au lieu de Self.
Un trait au lieu d’un type. impl Display for Point sans importer Display donne E0405, cannot find trait `Display` in this scope, avec help: consider importing this trait et use std::fmt::Display;. Même idée, même correction : ajoutez la ligne use. Voir Les traits.
Erreurs liées
Section intitulée « Erreurs liées »- E0425 : valeur ou fonction introuvable et, depuis Rust 1.93, type introuvable aussi. C’est le code que vous verrez réellement aujourd’hui.
- E0433 : la première partie d’un chemin comme
HashMap::new()oumodels::Userest introuvable. - E0432 : import non résolu, quand la ligne
useelle-même ne désigne rien. - E0603 : le type a été trouvé, mais il n’est pas
pub. - E0405 (trait introuvable) et E0411 (
Selfen dehors d’un impl) : les proches cousins présentés plus haut. - Toutes les erreurs du compilateur : la liste complète des pages d’erreurs.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Vous suivez un tutoriel qui montre error[E0412]: cannot find type, mais votre compilateur affiche error[E0425]: cannot find type. Pourquoi ?
2. fn first(items: &[T]) -> &T donne cannot find type T. Comment corriger ?
3. Une fonction dans mod billing utilise Order, une struct définie en haut de main.rs. Quelle ligne, dans le module, corrige le problème ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0412 — Rust error codes index (en anglais) : la page officielle, avec la remarque indiquant que ce code n’est plus émis, et les exemples classiques.
- E0425 — Rust error codes index (en anglais) : le code qu’utilise le compilateur actuel pour cette erreur.
- Generic Data Types — The Rust Book (en anglais) : comment déclarer
<T>, avec la même fonctionlargestque dans la solution 3. - Bringing Paths into Scope with the
useKeyword — The Rust Book (en anglais) :use,crate::etsuper::pour les types d’autres modules. std::prelude— documentation de la bibliothèque standard (en anglais) : la liste des noms utilisables sans les importer.