Errore Rust E0411: cannot find type Self in this scope (Self fuori da un impl)
E0411 significa che hai scritto Self in un punto dove Rust non riesce a capire che cosa rappresenta. Self è una scorciatoia per «il tipo di cui parla questo blocco impl (o questo trait)», quindi funziona solo dentro un impl, un trait o una definizione di tipo. La causa tipica è un costruttore come fn new() -> Self scritto al livello più esterno di un file, oppure un metodo copiato fuori dal suo blocco impl. È comune e si corregge in fretta. A differenza di E0412, che in Rust 1.93 è diventato E0425, questo codice non è cambiato: rustc 1.97 stampa ancora E0411. Fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0411]: cannot find type `Self` in this scope --> src/main.rs:5:21 |5 | fn new_counter() -> Self { // ❌ `Self` outside an `impl` | ----------- ^^^^ `Self` is only available in impls, traits, and type definitions | | | `Self` not allowed in a functionIl compilatore dice: non trova il tipo Self in questo scope, perché Self esiste solo negli impl, nei trait e nelle definizioni di tipo. Questo è il programma che produce l’errore:
struct Counter { count: u32,}
fn new_counter() -> Self { // ❌ `Self` outside an `impl` Counter { count: 0 }}
fn main() { let c = new_counter(); println!("{}", c.count);}Cosa significa
Sezione intitolata “Cosa significa”rustc ti indica due cose alla riga 5:
- Il
^^^^sottoSelf: «Selfis only available in impls, traits, and type definitions». È la regola, in una riga. - Il
-----sottonew_counter: «Selfnot allowed in a function» (Selfnon è ammesso in una funzione). Questo è il motivo qui:new_counterè una funzione normale, non fa parte di nessunimpl.
Tu sai che new_counter restituisce un Counter, perché hai appena scritto Counter { count: 0 }. Ma Rust non legge il corpo per indovinare che cosa significa Self. Self prende significato solo da un impl Counter { ... } o un trait ... { ... } che lo racchiude, e qui non ce n’è nessuno.
È come la parola «qui» su un post-it. Su una mappa, «tu sei qui» ha senso. Su un foglietto lasciato sul tavolo della cucina, nessuno sa dove sia «qui».
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Self non è un tipo a sé. È un segnaposto che ogni impl o trait riempie: dentro impl Counter, Self significa Counter; dentro impl Timer, significa Timer; dentro un trait, significa «qualunque tipo implementi questo trait». È proprio questo che lo rende utile: puoi rinominare la struct, o copiare un metodo in un altro impl, e Self si adegua.
Una funzione libera non appartiene a nessun tipo, quindi non c’è niente con cui riempire il segnaposto. Rust potrebbe provare a indovinare dal corpo, ma allora una firma dipenderebbe dal codice al suo interno, e Rust controlla di proposito le firme da sole. Vedi Struct in Rust per il posto abituale di fn new() -> Self.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: sposta la funzione in un blocco impl
Sezione intitolata “Soluzione 1: sposta la funzione in un blocco impl”Scegli questa nella maggior parte dei casi. Una funzione che crea un tipo o lavora con un tipo sta nel blocco impl di quel tipo, e lì Self funziona come ti aspettavi. Chiamala con 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);}Output:
2Dentro l’impl puoi usare Self sia come tipo (-> Self) sia per costruire un valore (Self { count: 0 }). Vedi Struct in Rust.
Soluzione 2: scrivi il nome del tipo al posto di Self
Sezione intitolata “Soluzione 2: scrivi il nome del tipo al posto di Self”Scegli questa quando la funzione deve restare una funzione libera, per esempio un helper che costruisce più tipi, o uno che vive in un altro modulo. Scrivi semplicemente il tipo vero, Counter, dove avevi scritto 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);}Output:
100È anche la correzione per un fn reset(c: &mut Self) copiato fuori da un impl: ogni Self nella firma e nel corpo diventa Counter.
Soluzione 3: usa un tipo generico se intendevi «un tipo qualsiasi»
Sezione intitolata “Soluzione 3: usa un tipo generico se intendevi «un tipo qualsiasi»”Scegli questa quando hai usato Self per dire «il tipo che vuole chi chiama»: è un lavoro per un generico T, non per Self. Dichiara <T> con i trait che servono alla funzione. Qui T: Default permette alla funzione di creare un valore iniziale di qualsiasi tipo:
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);}Output:
(0, 0)("", "")Se vuoi che ogni tipo decida come costruirsi, metti la funzione in un trait: trait Reset { fn fresh() -> Self; }. Dentro un trait, Self significa «il tipo che lo implementa». Vedi Generici in Rust e Trait in Rust.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Self { ... } in main o in una funzione libera. let c = Self { count: 0 }; dà E0411 con una prima riga leggermente diversa: cannot find struct, variant or union type `Self` in this scope. Correzione: scrivi Counter { count: 0 }, oppure chiama Counter::new().
Una funzione helper annidata dentro un metodo. Dentro impl Counter, un metodo che contiene una sua fn helper() -> Self riceve un codice diverso, E0401: can't use `Self` from outer item. Una funzione dentro una funzione non eredita l’impl esterno. Correzione: scrivi Counter nella funzione interna, oppure usa una closure, oppure sposta helper su nell’impl come metodo a sé.
Confondere Self e self. Self maiuscolo è il tipo; self minuscolo è il valore su cui si chiama un metodo. Usare self fuori da un metodo è un errore diverso, E0424. La correzione per entrambi: assicurati che il codice stia dentro il blocco impl giusto.
Errori correlati
Sezione intitolata “Errori correlati”- E0424:
self(minuscolo, il valore) usato fuori da un metodo. - E0425: non trova un valore, una funzione o (da Rust 1.93) un tipo con un nome normale.
- E0412: il vecchio codice per «cannot find type», ora segnalato come E0425.
- E0405: non trova un trait, di solito manca una riga
use. - E0401:
Selfdi unimplesterno usato dentro una funzione annidata, vedi sopra. - Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Dove puoi usare Self come tipo?
2. fn make_user() -> Self al livello più esterno dà E0411. Qual è la correzione abituale?
3. Dentro impl Counter, che cosa crea Self { count: 0 }?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0411 — Rust error codes index (in inglese): la spiegazione ufficiale di che cosa rappresenta
Selfe perché funziona solo in un impl, un trait o una definizione di tipo. - Method Syntax — The Rust Book (in inglese): funzioni associate come
fn square(size: u32) -> Self, e come funzionaSelfin unimpl. - The
Selfkeyword — documentazione della libreria standard (in inglese): che cosa significaSelfnegli impl, nei trait e nelle definizioni di tipo. Selfin paths — The Rust Reference (in inglese): le regole esatte, compreso il motivo per cui gli item annidati non possono usare unSelfesterno.