Errore Rust E0255: the name is defined multiple times (import e item locale)
E0255 significa che una riga use e qualcosa che hai definito tu hanno lo stesso nome. Il caso classico: importi std::io::Error in cima al file e più sotto scrivi il tuo enum Error. Rust non può lasciare che un nome significhi due cose, quindi si ferma. È un errore molto comune quando inizi a scrivere i tuoi tipi di errore, e la correzione è una riga corta. A differenza di E0412, questo codice non è cambiato nelle versioni recenti: rustc 1.97 lo segnala ancora come E0255. Fa parte della guida agli errori del compilatore.
Il messaggio di errore
Sezione intitolata “Il messaggio di errore”error[E0255]: the name `Error` is defined multiple times --> src/main.rs:3:1 |1 | use std::io::Error; | -------------- previous import of the type `Error` here2 |3 | enum Error { // ❌ same name as the import on line 1 | ^^^^^^^^^^ `Error` redefined here | = note: `Error` must be defined only once in the type namespace of this modulehelp: you can use `as` to change the binding name of the import |1 | use std::io::Error as OtherError; | +++++++++++++
warning: unused import: `std::io::Error` --> src/main.rs:1:5 |1 | use std::io::Error; | ^^^^^^^^^^^^^^Il compilatore dice: il nome Error è definito più volte, una volta dall’import e una volta dal tuo enum. Questo è il programma che produce l’errore:
use std::io::Error;
enum Error { // ❌ same name as the import on line 1 EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn main() { match check_name("") { Ok(()) => println!("name is fine"), Err(Error::EmptyName) => println!("name is empty"), Err(Error::TooLong(n)) => println!("name has {} letters, max is 10", n), }}Cosa significa
Sezione intitolata “Cosa significa”rustc ti indica tre cose:
- La riga con
---(riga 1): «previous import of the typeErrorhere» (import precedente del tipoError). La rigauseha già messo un nomeErrorin questo modulo. - La riga con
^^^(riga 3): «Errorredefined here» (Errorridefinito qui). Il tuoenum Errorcerca di prendere lo stesso nome. - L’
help:ti offre una via d’uscita: dare all’import un nome locale diverso conas.
Il warning: unused import più sotto è un indizio utile. Significa che niente nel tuo codice usa davvero std::io::Error (ogni Error in questo programma indica il tuo enum). In quel caso puoi semplicemente cancellare la riga 1. Se invece ti servono tutti e due, continua a leggere.
La nota parla del type namespace (lo spazio dei nomi dei tipi). Tipi, trait e moduli condividono una lista di nomi; funzioni, costanti e static ne condividono un’altra. Quindi use std::mem::swap; più una tua fn swap danno lo stesso errore, ma nel «value namespace» (lo spazio dei nomi dei valori).
Pensa a una classe con due alunni che si chiamano Alex. L’insegnante non può più chiamare semplicemente «Alex». Qualcuno ha bisogno di un soprannome, come «Alex B.», ed è proprio quello che as dà a un import.
Perché Rust si comporta così
Sezione intitolata “Perché Rust si comporta così”In un modulo, un nome indica esattamente un item. Quando Rust legge Error::EmptyName alla riga 10, deve sapere quale Error intendi, e si rifiuta di tirare a indovinare. Se scegliesse in silenzio il tuo enum, la tua riga use non farebbe niente; se scegliesse io::Error, il tuo enum sarebbe irraggiungibile. In entrambi i casi una scelta silenziosa nasconderebbe un errore.
Per questo E0255 è parente di E0428 (due tuoi item con lo stesso nome) e di E0252 (due righe use con lo stesso nome). La regola è la stessa: un nome, una cosa, per modulo. Vedi Moduli in Rust per capire come funziona use.
Come risolverlo
Sezione intitolata “Come risolverlo”Soluzione 1: rinomina l’import con as
Sezione intitolata “Soluzione 1: rinomina l’import con as”Scegli questa quando ti servono entrambi i tipi nello stesso file, cosa frequente: il tuo Error per le regole della tua app e io::Error per file e rete. Dai all’import un soprannome che dica da dove viene. IoError si legge meglio del segnaposto di rustc OtherError:
use std::io::Error as IoError;use std::io::ErrorKind;
#[derive(Debug)]enum Error { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn save_name(name: &str) -> Result<(), IoError> { if name == "root" { return Err(IoError::new(ErrorKind::PermissionDenied, "quel nome è riservato")); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris")); println!("{:?}", check_name("")); println!("{:?}", check_name("Ferris the Crab")); match save_name("root") { Ok(()) => println!("salvato"), Err(e) => println!("errore di I/O: {}", e), }}Output:
Ok(())Err(EmptyName)Err(TooLong(15))errore di I/O: quel nome è riservatoIl nome "Ferris the Crab" resta in inglese perché il programma ne conta i byte con .len(): con lettere accentate il numero cambierebbe. as cambia il nome solo in questo file. Ovunque altrove il tipo resta std::io::Error.
Soluzione 2: importa il modulo, non il tipo
Sezione intitolata “Soluzione 2: importa il modulo, non il tipo”Scegli questa quando vuoi che ogni Error mostri da dove viene a ogni uso. Importa il modulo genitore con use std::io; e scrivi io::Error. Il tuo Error tiene il nome corto. Molti programmatori Rust preferiscono questo stile per i tipi con nomi comuni come Error e Result:
use std::io;
enum Error { EmptyName,}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } Ok(())}
fn save_name(name: &str) -> Result<(), io::Error> { if name == "root" { return Err(io::Error::new(io::ErrorKind::PermissionDenied, "nome riservato")); } Ok(())}
fn main() { if let Err(Error::EmptyName) = check_name("") { println!("il nome è vuoto"); } if let Err(e) = save_name("root") { println!("errore di I/O: {}", e); }}Output:
il nome è vuotoerrore di I/O: nome riservatoSoluzione 3: rinomina il tuo item
Sezione intitolata “Soluzione 3: rinomina il tuo item”Scegli questa quando il tuo tipo verrà usato in molti file, o da altre persone. Un nome specifico come NameError o AppError è più chiaro di un secondo Error, e la riga use può restare com’è:
use std::io::Error;
#[derive(Debug)]enum NameError { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), NameError> { if name.is_empty() { return Err(NameError::EmptyName); } if name.len() > 10 { return Err(NameError::TooLong(name.len())); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris the Crab")); let disk = Error::other("il disco è pieno"); println!("{}", disk);}Output:
Err(TooLong(15))il disco è pienoNei progetti più grandi, il crate thiserror rende molto più corto scrivere enum di errore come questo. Vedi Errori personalizzati in Rust.
Soluzione 4: cancella l’import che non usi
Sezione intitolata “Soluzione 4: cancella l’import che non usi”Scegli questa quando rustc stampa anche warning: unused import, come nell’errore qui sopra. L’import è rimasto da codice precedente, o l’ha aggiunto il tuo editor. Togli la riga, e il programma in cima a questa pagina funziona così com’è:
enum Error { EmptyName, TooLong(usize),}
fn check_name(name: &str) -> Result<(), Error> { if name.is_empty() { return Err(Error::EmptyName); } if name.len() > 10 { return Err(Error::TooLong(name.len())); } Ok(())}
fn main() { match check_name("") { Ok(()) => println!("il nome va bene"), Err(Error::EmptyName) => println!("il nome è vuoto"), Err(Error::TooLong(n)) => println!("il nome ha {} lettere, il massimo è 10", n), }}Output:
il nome è vuotoDove lo incontri di solito
Sezione intitolata “Dove lo incontri di solito”Una tua funzione con un nome della libreria standard. use std::mem::swap; più fn swap(a: &mut i32, b: &mut i32) danno E0255 con «previous import of the value swap here» e la nota «value namespace». Correzione: chiama la tua swap_values, oppure togli l’import se volevi davvero scrivere la tua.
Copia-incolla tra moduli. Sposti struct User in mod models, aggiungi use models::User; in cima, ma ti dimentichi di cancellare la vecchia struct User in main.rs. Correzione: cancella la vecchia copia, così User indica solo quella in models.
Un trait con un nome della libreria standard. use std::fmt::Display; e un tuo trait Display vanno in conflitto allo stesso modo («previous import of the trait Display»). Correzione: rinomina il tuo trait (Describe, Render), oppure scrivi use std::fmt; e fmt::Display.
Buono a sapersi: un import glob come use std::io::*; non causa mai E0255. I tuoi item vincono in silenzio sui nomi che arrivano tramite un *. È comodo, ma può anche nascondere quale Error stai usando, quindi di solito gli import espliciti sono più chiari.
Errori correlati
Sezione intitolata “Errori correlati”- E0252: due righe
useportano lo stesso nome, comefmt::Resulteio::Result. - E0428: due item tuoi hanno lo stesso nome, spesso perché cerchi di fare l’overloading di una funzione.
- E0592: due metodi con lo stesso nome in un blocco
impl. - E0432: la riga
usestessa indica qualcosa che non esiste. - E0425: il problema opposto, un nome che non è definito affatto dove lo usi.
- Tutti gli errori del compilatore: l’elenco completo delle pagine sugli errori.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Il tuo file inizia con use std::fmt::Result; e più sotto definisce enum Result { Pass, Fail }. Che errore ottieni?
2. Ti servono sia std::io::Error sia un tuo enum Error nello stesso file. Qual è una correzione pulita?
3. rustc mostra E0255 e anche warning: unused import: std::io::Error. Che cosa ti dice il warning?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- E0255 — Rust error codes index (in inglese): la spiegazione ufficiale, con un
use bar::foo;in conflitto confn foo, risolto conaso con il percorso del genitore. - Providing New Names with the
asKeyword — The Rust Book (in inglese): comeasrinomina un import, con i due tipiResult. - Use declarations — The Rust Reference (in inglese): ogni forma di
use, compresias, i gruppi e i glob. - Namespaces — The Rust Reference (in inglese): il type namespace e il value namespace citati nella nota dell’errore.
- The
usedeclaration — Rust by Example (in inglese): esempi brevi ed eseguibili di import e rinomina.