Aller au contenu

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.

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 here
2 | 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 here
2 | 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.

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 T sans 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.

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.

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 EUR
▶ Essayez par vous-même

Solution 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)
true
▶ Essayez par vous-même

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

100
y
▶ Essayez par vous-même

C’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 EUR
▶ Essayez par vous-même

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

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.

  • 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() ou models::User est introuvable.
  • E0432 : import non résolu, quand la ligne use elle-même ne désigne rien.
  • E0603 : le type a été trouvé, mais il n’est pas pub.
  • E0405 (trait introuvable) et E0411 (Self en 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

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