Erreur Rust E0411 : cannot find type Self in this scope (Self hors d'un impl)
E0411 veut dire que vous avez écrit Self à un endroit où Rust ne peut pas savoir ce qu’il représente. Self est un raccourci pour « le type dont parle ce bloc impl (ou ce trait) », il ne marche donc qu’à l’intérieur d’un impl, d’un trait ou d’une définition de type. La cause habituelle : un constructeur comme fn new() -> Self écrit au premier niveau d’un fichier, ou une méthode que vous avez copiée hors de son bloc impl. C’est une erreur courante et vite corrigée. Contrairement à E0412, devenue E0425 avec Rust 1.93, ce code n’a pas changé : rustc 1.97 affiche toujours E0411. Cette page fait partie du guide des erreurs du compilateur Rust.
Le message d’erreur
Section intitulée « Le message d’erreur »error[E0411]: cannot find type `Self` in this scope --> src/main.rs:5:21 |5 | fn new_counter() -> Self { // ❌ `Self` hors d'un `impl` | ----------- ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a functionLe compilateur vous dit : « impossible de trouver le type Self dans cette portée ». La section « Ce que ça veut dire » ci-dessous traduit chaque ligne.
Voici le programme qui la provoque :
struct Counter { count: u32,}
fn new_counter() -> Self { // ❌ `Self` hors d'un `impl` Counter { count: 0 }}
fn main() { let c = new_counter(); println!("{}", c.count);}Ce que ça veut dire
Section intitulée « Ce que ça veut dire »rustc pointe deux choses sur la ligne 5 :
- Les
^^^^sousSelf: «Selfis only available in impls, traits, and type definitions » (Selfn’est disponible que dans les impl, les traits et les définitions de type). C’est la règle, en une ligne. - Les
-----sousnew_counter: «Selfnot allowed in a function » (Selfn’est pas autorisé dans une fonction). C’est la raison ici :new_counterest une fonction ordinaire, qui ne fait partie d’aucunimpl.
Vous savez peut-être que new_counter renvoie un Counter, puisque vous venez d’écrire Counter { count: 0 }. Mais Rust ne lit pas le corps de la fonction pour deviner ce que veut dire Self. Self ne prend son sens que grâce à un impl Counter { ... } ou un trait ... { ... } qui l’entoure, et ici il n’y en a aucun.
C’est comme le mot « ici » sur un post-it. Sur un plan, « vous êtes ici » a un sens. Sur un post-it posé sur la table de la cuisine, personne ne sait où est « ici ».
Pourquoi Rust fait ça
Section intitulée « Pourquoi Rust fait ça »Self n’est pas un type à part entière. C’est un emplacement réservé que chaque impl ou trait remplit : dans impl Counter, Self veut dire Counter ; dans impl Timer, il veut dire Timer ; dans un trait, il veut dire « le type, quel qu’il soit, qui implémente ce trait ». C’est ce qui le rend utile : vous pouvez renommer la struct, ou copier une méthode dans un autre impl, et Self suit le mouvement.
Une fonction libre n’appartient à aucun type, il n’y a donc rien pour remplir l’emplacement. Rust pourrait essayer de deviner d’après le corps, mais alors une signature dépendrait du code qu’elle contient, et Rust vérifie volontairement les signatures toutes seules. Voir Les fonctions de type constructeur pour la place habituelle de fn new() -> Self.
Comment corriger
Section intitulée « Comment corriger »Solution 1 : déplacer la fonction dans un bloc impl
Section intitulée « Solution 1 : déplacer la fonction dans un bloc impl »Choisissez-la la plupart du temps. Une fonction qui crée un type ou travaille avec lui a sa place dans le bloc impl de ce type, et là, Self fonctionne comme vous l’attendiez. Appelez-la avec Counter::new() :
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Self { count: 0 } }
fn increment(&mut self) { self.count += 1; }}
fn main() { let mut c = Counter::new(); c.increment(); c.increment(); println!("{}", c.count);}Sortie :
2Dans l’impl, vous pouvez utiliser Self à la fois comme type (-> Self) et pour construire une valeur (Self { count: 0 }). Voir Ajouter du comportement avec des méthodes.
Solution 2 : écrire le nom du type au lieu de Self
Section intitulée « Solution 2 : écrire le nom du type au lieu de Self »Choisissez-la quand la fonction doit rester une fonction libre, par exemple une fonction d’aide qui construit plusieurs types, ou une fonction qui vit dans un autre module. Écrivez simplement le vrai type, Counter, là où vous aviez écrit Self :
struct Counter { count: u32,}
fn new_counter(start: u32) -> Counter { Counter { count: start }}
fn reset(c: &mut Counter) { c.count = 0;}
fn main() { let mut c = new_counter(10); println!("{}", c.count); reset(&mut c); println!("{}", c.count);}Sortie :
100C’est aussi la correction pour un fn reset(c: &mut Self) copié hors d’un impl : chaque Self de la signature et du corps devient Counter.
Solution 3 : utiliser un type générique si vous vouliez dire « n’importe quel type »
Section intitulée « Solution 3 : utiliser un type générique si vous vouliez dire « n’importe quel type » »Choisissez-la quand vous avez utilisé Self pour dire « le type que l’appelant voudra », ce qui est le travail d’un générique T, pas de Self. Déclarez <T> avec les traits dont la fonction a besoin. Ici, T: Default permet à la fonction de créer une valeur de départ de n’importe quel type :
fn fresh_pair<T: Default>() -> (T, T) { (T::default(), T::default())}
fn main() { let numbers: (u32, u32) = fresh_pair(); let words: (String, String) = fresh_pair(); println!("{:?}", numbers); println!("{:?}", words);}Sortie :
(0, 0)("", "")Si vous voulez que chaque type décide lui-même comment il se construit, mettez la fonction dans un trait : trait Reset { fn fresh() -> Self; }. Dans un trait, Self veut dire « le type qui l’implémente ». Voir Les génériques et Définir un trait.
Où vous le verrez souvent
Section intitulée « Où vous le verrez souvent »Self { ... } dans main ou dans une fonction libre. let c = Self { count: 0 }; donne E0411 avec un titre un peu différent : cannot find struct, variant or union type `Self` in this scope (impossible de trouver une struct, une variante ou une union Self dans cette portée). Correction : écrivez Counter { count: 0 }, ou appelez Counter::new().
Une fonction d’aide imbriquée dans une méthode. Dans impl Counter, une méthode qui contient sa propre fn helper() -> Self donne un autre code, E0401 : can't use `Self` from outer item (impossible d’utiliser le Self de l’élément extérieur). Une fonction dans une fonction n’hérite pas de l’impl extérieur. Correction : écrivez Counter dans la fonction intérieure, utilisez une closure (fonction anonyme), ou remontez helper dans l’impl comme méthode à part entière.
Confondre Self et self. Self avec une majuscule, c’est le type ; self en minuscules, c’est la valeur sur laquelle une méthode est appelée. Utiliser self en dehors d’une méthode est une autre erreur, E0424. Correction dans les deux cas : vérifiez que le code se trouve dans le bon bloc impl.
Erreurs liées
Section intitulée « Erreurs liées »- E0424 :
self(en minuscules, la valeur) utilisé en dehors d’une méthode. - E0425 : impossible de trouver une valeur, une fonction ou (depuis Rust 1.93) un type au nom ordinaire.
- E0412 : l’ancien code pour « cannot find type », signalé aujourd’hui en E0425.
- E0405 : impossible de trouver un trait, en général à cause d’une ligne
useoubliée. - E0401 : le
Selfd’unimplextérieur utilisé dans une fonction imbriquée, présenté 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. Où pouvez-vous utiliser Self comme type ?
2. fn make_user() -> Self au premier niveau du fichier donne E0411. Quelle est la correction habituelle ?
3. Dans impl Counter, que crée Self { count: 0 } ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- E0411 — Rust error codes index (en anglais) : l’explication officielle de ce que représente
Self, et pourquoi il ne marche que dans un impl, un trait ou une définition de type. - Method Syntax — The Rust Book (en anglais) : les fonctions associées comme
fn square(size: u32) -> Self, et le fonctionnement deSelfdans unimpl. - The
Selfkeyword — standard library docs (en anglais) : ce que veut direSelfdans les impl, les traits et les définitions de type. Selfin paths — The Rust Reference (en anglais) : les règles exactes, y compris pourquoi les éléments imbriqués ne peuvent pas utiliser leSelfextérieur.