Errore Rust E0592: duplicate definitions with name X (metodo definito due volte)
E0592 significa: lo stesso tipo ha due metodi, funzioni associate o costanti con lo stesso nome, scritti nei blocchi impl. Un tipo può avere tutti i blocchi impl che vuoi, ma condividono tutti un’unica lista di nomi, quindi ogni nome si può usare una volta sola. Di solito nasce da un copia-incolla, da un merge o da un secondo blocco impl in un altro file. La correzione è tenerne uno solo, o dare all’altro un nome nuovo. (Questa pagina fa parte di Errori del compilatore Rust spiegati.)
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0592]: duplicate definitions with name `reset` --> src/main.rs:10:5 |10 | fn reset(&mut self) { | ^^^^^^^^^^^^^^^^^^^ duplicate definitions for `reset`...16 | fn reset(&mut self) { // ❌ `reset` is already defined above | ------------------- other definition for `reset`Il compilatore dice: ci sono due definizioni con il nome reset. Questo è il programma che produce l’errore:
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn reset(&mut self) { self.count = 0; }}
impl Counter { fn reset(&mut self) { // ❌ `reset` is already defined above self.count = 0; }}
fn main() { let mut c = Counter::new(); c.reset(); println!("{}", c.count);}rustc segnala anche E0034, «multiple applicable items in scope», sulla chiamata c.reset(), perché non sa quale dei due reset intendi. È un errore di conseguenza: correggi E0592 e sparisce anche E0034.
Cosa significa
Sezione intitolata “Cosa significa”La prima riga ti dà il nome definito due volte (reset). Il ^^^ segna una definizione, e la riga con --- segna l’«other definition» (l’altra definizione). rustc mostra i numeri di riga di entrambe, così puoi saltarci subito. Quando sono lontane, i ... in mezzo significano solo «alcune righe saltate».
Non conta che i due reset siano in blocchi impl Counter diversi, o persino in file diversi del tuo crate. Per Rust sono tutti metodi dello stesso tipo, quindi Counter::reset deve indicare esattamente una funzione. La stessa regola vale per le costanti associate: due const MAX: u32 per lo stesso tipo danno anche loro E0592.
È come una rubrica del telefono con due contatti chiamati «Mamma». Quando dici «chiama la mamma», che numero deve comporre?
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”Dividere i metodi in più blocchi impl è permesso e spesso utile: un blocco per i costruttori, uno per i getter, uno dietro un #[cfg(test)]. Vedi Struct in Rust. Però quando chiami c.reset() o Counter::reset(&mut c), Rust deve trovare una funzione. Se ce ne fossero due, quale viene eseguita dipenderebbe da dettagli che nessuno vede leggendo la chiamata.
Per questo Rust rifiuta già la definizione, non solo la chiamata. Così cattura un bug vero: con un metodo copiato e incollato potresti correggere un problema in una copia, mentre l’altra copia continua a girare. Rust si assicura che ci sia sempre una sola versione da correggere.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: elimina il doppione e tieni una sola definizione
Sezione intitolata “Soluzione 1: elimina il doppione e tieni una sola definizione”Scegli questa nella maggior parte dei casi. Se le due copie fanno la stessa cosa (copia-incolla, un merge disordinato, un metodo che hai spostato senza toglierlo), eliminane una. Prima di eliminare, confronta i due corpi: se uno contiene una correzione che l’altro non ha, tieni quello. Unire i blocchi impl in uno solo rende anche più facile notare i doppioni in futuro.
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn increment(&mut self) { self.count += 1; }
fn reset(&mut self) { // ✅ un solo `reset` per `Counter` self.count = 0; }}
fn main() { let mut c = Counter::new(); c.increment(); c.increment(); println!("prima del reset: {}", c.count); c.reset(); println!("dopo il reset: {}", c.count);}Output:
prima del reset: 2dopo il reset: 0Se non trovi la seconda definizione, cerca in tutto il progetto: grep -rn "fn reset" src/. Un blocco impl Counter può stare in qualsiasi modulo del tuo crate.
Soluzione 2: rinomina uno dei due
Sezione intitolata “Soluzione 2: rinomina uno dei due”Scegli questa quando le due definizioni fanno cose diverse. Rust non ha l’overloading: non puoi avere due metodi con lo stesso nome e parametri diversi, come reset() e reset(start: u32). Anche questo è E0592. Dai a ciascuno un nome che dica che cosa fa:
struct Counter { count: u32,}
impl Counter { fn new() -> Self { Counter { count: 0 } }
fn reset(&mut self) { self.count = 0; }}
impl Counter { fn reset_to(&mut self, start: u32) { // ✅ un nome diverso per un comportamento diverso self.count = start; }}
fn main() { let mut c = Counter::new(); c.reset_to(10); println!("dopo reset_to(10): {}", c.count); c.reset(); println!("dopo reset(): {}", c.count);}Output:
dopo reset_to(10): 10dopo reset(): 0Qui aiutano le convenzioni di nomi tipiche di Rust: new e with_capacity, from_str e from_bytes, get e get_mut. Se vuoi davvero un solo nome per diversi tipi di argomento, usa un parametro generico o un trait, come fn reset_to(&mut self, start: impl Into<u32>). Vedi Generici in Rust.
Soluzione 3: evita che i blocchi impl generici si sovrappongano
Sezione intitolata “Soluzione 3: evita che i blocchi impl generici si sovrappongano”Scegli questa quando una delle due definizioni sta in un blocco generico come impl<T> Wrapper<T>. Quel blocco copre anche Wrapper<i32>, quindi un secondo impl Wrapper<i32> con lo stesso nome di metodo è un doppione:
error[E0592]: duplicate definitions with name `describe` --> src/main.rs:4:5 | 4 | fn describe(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `describe`...10 | fn describe(&self) -> String { | ---------------------------- other definition for `describe`Il programma che lo produce:
struct Wrapper<T>(T);
impl<T> Wrapper<T> { fn describe(&self) -> String { String::from("something") }}
impl Wrapper<i32> { fn describe(&self) -> String { format!("the number {}", self.0) }}
fn main() { println!("{}", Wrapper(5).describe());}Rust non permette a un impl specifico di sovrascrivere uno generico (quella funzionalità, chiamata specialization, non è stabile). Hai due buone vie d’uscita: scrivere blocchi impl solo per tipi specifici, così non possono sovrapporsi, oppure mettere il comportamento in un trait e implementarlo una volta per tipo:
struct Wrapper<T>(T);
// Opzione A: i blocchi impl per tipi specifici non si sovrappongono maiimpl Wrapper<i32> { fn describe(&self) -> String { format!("il numero {}", self.0) }}
impl Wrapper<&str> { fn describe(&self) -> String { format!("il testo \"{}\"", self.0) }}
// Opzione B: un trait, implementato una volta per tipotrait Label { fn label(&self) -> String;}
impl Label for i32 { fn label(&self) -> String { format!("intero {}", self) }}
impl Label for bool { fn label(&self) -> String { format!("flag {}", self) }}
impl<T: Label> Wrapper<T> { fn label(&self) -> String { self.0.label() // un solo metodo generico, la parte per tipo vive nel trait }}
fn main() { println!("{}", Wrapper(5).describe()); println!("{}", Wrapper("ciao").describe()); println!("{}", Wrapper(7).label()); println!("{}", Wrapper(true).label());}Output:
il numero 5il testo "ciao"intero 7flag trueDi solito la versione con il trait è il design migliore sul lungo periodo: aggiungere il supporto a un nuovo tipo richiede solo un altro impl Label for .... Vedi Trait in Rust.
Dove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Un helper per i test in un secondo blocco impl. Aggiungi impl Counter { fn new() -> Self { ... } } dentro #[cfg(test)] mod tests per costruire valori di prova, ma Counter::new esiste già. Anche il blocco dei test è un impl Counter. Correzione: chiamalo per esempio fn for_test(), oppure usa il vero new. Vedi Test in Rust.
Dopo un merge o un refactoring. Due branch hanno aggiunto entrambi un fn len(&self), oppure un metodo è stato spostato in un nuovo file e la vecchia copia è rimasta. rustc mostra entrambi i numeri di riga; tieni quella migliore.
Un metodo di trait con lo stesso nome va bene. impl Counter { fn reset(&mut self) } insieme a impl Resettable for Counter { fn reset(&mut self) } non è E0592: uno è il metodo proprio del tipo, l’altro appartiene al trait, e c.reset() chiama quello del tipo. Anche due trait con lo stesso nome di metodo compilano, ma chiamarlo con c.reset() dà E0034; si risolve con Resettable::reset(&mut c).
Errori correlati
Sezione intitolata “Errori correlati”- E0034: multiple applicable items in scope: l’errore di conseguenza nel punto della chiamata, e l’errore per due trait con lo stesso nome di metodo.
- E0428: the name is defined multiple times: lo stesso sbaglio per gli item di un modulo, come due
struct Countero due funzioni liberefn main. - E0599: no method named x found: il problema opposto, un metodo che non esiste proprio.
- E0255: nome già usato da un import ed E0252: nome importato due volte: nomi doppi causati da
use. - Tutti gli errori del compilatore spiegati
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Un tipo ha due blocchi impl. Possono contenere entrambi un metodo chiamato reset?
2. Vuoi area() e area(scale: f64). Che cosa fai in Rust?
3. Perché impl<T> Wrapper<T> e impl Wrapper<i32> vanno in conflitto se entrambi definiscono describe?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0592 — Rust error codes index (in inglese): la spiegazione ufficiale di questo errore.
- Method Syntax — The Rust Book (in inglese): metodi, funzioni associate e la sezione «Multiple
implBlocks». - Generic Data Types — The Rust Book (in inglese):
impl<T> Point<T>accanto aimpl Point<f32>, e come si relazionano. - Implementations — The Rust Reference (in inglese): le regole esatte dei blocchi
implpropri di un tipo e dei loro item associati. - E0034 — Rust error codes index (in inglese): la pagina ufficiale dell’errore di conseguenza «multiple applicable items».