Salta ai contenuti

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.

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 function

Il 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);
}

rustc ti indica due cose alla riga 5:

  1. Il ^^^^ sotto Self: «Self is only available in impls, traits, and type definitions». È la regola, in una riga.
  2. Il ----- sotto new_counter: «Self not allowed in a function» (Self non è ammesso in una funzione). Questo è il motivo qui: new_counter è una funzione normale, non fa parte di nessun impl.

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

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.

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:

2
▶ Provalo tu

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

10
0
▶ Provalo tu

È 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)
("", "")
▶ Provalo tu

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.

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.

  • 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: Self di un impl esterno usato dentro una funzione annidata, vedi sopra.
  • Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.

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