Erro E0255 do Rust: the name is defined multiple times (import vs item local)
O E0255 quer dizer que uma linha use e algo que você mesmo definiu têm o mesmo nome. O caso clássico: você importa std::io::Error no topo do arquivo e, mais abaixo, escreve o seu próprio enum Error. O Rust não deixa um nome significar duas coisas, então ele para. É um erro muito comum quando você começa a escrever os seus próprios tipos de erro, e a correção é uma linha curta. Ao contrário do E0412, este código não mudou nas versões recentes: o rustc 1.97 continua mostrando E0255. Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”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 { // ❌ mesmo nome do import da linha 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; | ^^^^^^^^^^^^^^Em português: “o nome Error foi definido várias vezes”. O rustc mostra o import anterior, a redefinição, uma nota sobre o namespace de tipos, uma sugestão com as e, no fim, um aviso de import não usado.
Este é o programa que gera o erro:
use std::io::Error;
enum Error { // ❌ mesmo nome do import da linha 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!("o nome está ok"), Err(Error::EmptyName) => println!("o nome está vazio"), Err(Error::TooLong(n)) => println!("o nome tem {} letras, o máximo é 10", n), }}O que significa
Seção intitulada “O que significa”O rustc aponta para três coisas:
- A linha
---(linha 1): “previous import of the typeErrorhere” (import anterior do tipoErroraqui). A linhausejá colocou um nomeErrorneste módulo. - A linha
^^^(linha 3): “Errorredefined here” (Errorredefinido aqui). O seuenum Errortenta ocupar o mesmo nome. - O
help:oferece uma saída: dar ao import outro nome local comas.
O warning: unused import (import não usado) logo abaixo é uma pista útil. Ele quer dizer que nada no seu código usa de verdade o std::io::Error (todo Error neste programa é o seu enum). Nesse caso, você pode simplesmente apagar a linha 1. Se você precisa dos dois, continue lendo.
A nota fala do type namespace (namespace de tipos). Tipos, traits e módulos dividem uma lista de nomes; funções, constantes e statics dividem outra. Por isso use std::mem::swap; mais uma fn swap sua dá o mesmo erro, só que no “value namespace” (namespace de valores).
Pense numa sala de aula com dois alunos chamados Alex. A professora não pode mais só chamar “Alex”. Alguém precisa de um apelido, como “Alex B.”, e é exatamente isso que o as dá a um import.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Um nome num módulo aponta para exatamente um item. Quando o Rust lê Error::EmptyName na linha 10, ele precisa saber de qual Error você está falando, e se recusa a adivinhar. Se ele escolhesse o seu enum em silêncio, a sua linha use não faria nada; se escolhesse o io::Error, o seu enum ficaria inacessível. De um jeito ou de outro, uma escolha silenciosa esconderia um engano.
É por isso que o E0255 é irmão do E0428 (dois itens seus com o mesmo nome) e do E0252 (duas linhas use com o mesmo nome). A regra é a mesma: um nome, uma coisa, por módulo. Veja em Módulos como o use funciona.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Renomeie o import com as
Seção intitulada “Correção 1: Renomeie o import com as”Escolha esta quando você precisa dos dois tipos no mesmo arquivo, o que é comum: o seu próprio Error para as regras do seu programa e o io::Error para arquivos e rede. Dê ao import um apelido que diga de onde ele vem. IoError fica mais claro que o OtherError provisório do rustc:
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, "esse nome é reservado")); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris")); println!("{:?}", check_name("")); println!("{:?}", check_name("Ferris the Crab")); match save_name("root") { Ok(()) => println!("salvo"), Err(e) => println!("erro de E/S: {}", e), }}Saída:
Ok(())Err(EmptyName)Err(TooLong(15))erro de E/S: esse nome é reservadoO as só muda o nome neste arquivo. Em todos os outros lugares, o tipo continua sendo std::io::Error.
Correção 2: Importe o módulo, não o tipo
Seção intitulada “Correção 2: Importe o módulo, não o tipo”Escolha esta quando você quer que cada Error mostre de onde vem em todo lugar em que aparece. Importe o módulo pai com use std::io; e escreva io::Error. O seu próprio Error fica com o nome curto. Muitos programadores Rust preferem esse estilo para tipos com nomes comuns como 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 reservado")); } Ok(())}
fn main() { if let Err(Error::EmptyName) = check_name("") { println!("o nome está vazio"); } if let Err(e) = save_name("root") { println!("erro de E/S: {}", e); }}Saída:
o nome está vazioerro de E/S: nome reservadoCorreção 3: Renomeie o seu próprio item
Seção intitulada “Correção 3: Renomeie o seu próprio item”Escolha esta quando o seu tipo vai ser usado em muitos arquivos, ou por outras pessoas. Um nome específico como NameError ou AppError é mais claro que um segundo Error, e a linha use pode ficar como está:
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("disco cheio"); println!("{}", disk);}Saída:
Err(TooLong(15))disco cheioEm projetos maiores, o crate thiserror deixa esses enums de erro bem mais curtos de escrever. Veja Erros personalizados.
Correção 4: Apague o import que você não usa
Seção intitulada “Correção 4: Apague o import que você não usa”Escolha esta quando o rustc também mostra warning: unused import, como no erro acima. O import sobrou de um código antigo, ou foi colocado pelo seu editor. Tire a linha, e o programa do começo desta página funciona como foi escrito:
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!("o nome está ok"), Err(Error::EmptyName) => println!("o nome está vazio"), Err(Error::TooLong(n)) => println!("o nome tem {} letras, o máximo é 10", n), }}Saída:
o nome está vazioOnde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Uma função sua com um nome da std. use std::mem::swap; mais fn swap(a: &mut i32, b: &mut i32) dá E0255 com “previous import of the value swap here” (import anterior do valor swap aqui) e a nota “value namespace”. Correção: chame a sua de swap_values, ou tire o import se você queria mesmo escrever a sua.
Copiar e colar entre módulos. Você move a struct User para dentro de mod models, acrescenta use models::User; no topo, mas esquece de apagar a struct User antiga no main.rs. Correção: apague a cópia antiga, para que User signifique só a de models.
Um trait com um nome da std. use std::fmt::Display; e um trait Display seu se chocam do mesmo jeito (“previous import of the trait Display”). Correção: renomeie o seu trait (Describe, Render), ou escreva use std::fmt; e fmt::Display.
Bom saber: um import glob como use std::io::*; nunca causa E0255. Os seus próprios itens ganham, sem aviso, dos nomes que entram por um *. Isso é prático, mas também pode esconder qual Error você está usando, então imports explícitos costumam ser mais claros.
Erros relacionados
Seção intitulada “Erros relacionados”- E0252: duas linhas
usetrazem o mesmo nome, comofmt::Resulteio::Result. - E0428: dois itens seus têm o mesmo nome, muitas vezes por tentar sobrecarregar uma função.
- E0592: dois métodos com o mesmo nome num bloco
impl. - E0432: a própria linha
useaponta para algo que não existe. - E0425: o problema contrário: um nome que não está definido onde você o usa.
- Todos os erros do compilador: a lista completa de páginas de erro.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O seu arquivo começa com use std::fmt::Result; e mais abaixo define enum Result { Pass, Fail }. Qual erro você recebe?
2. Você precisa do std::io::Error e do seu próprio enum Error no mesmo arquivo. Qual é uma correção limpa?
3. O rustc mostra E0255 e também warning: unused import: std::io::Error. O que o aviso diz?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0255 — Rust error codes index (em inglês): a explicação oficial, com um
use bar::foo;que se choca comfn foo, corrigido comasou com o caminho do módulo pai. - Providing New Names with the
asKeyword — The Rust Book (em inglês): como oasrenomeia um import, com os dois tiposResult. - Use declarations — The Rust Reference (em inglês): todas as formas de
use, incluindoas, grupos e globs. - Namespaces — The Rust Reference (em inglês): os namespaces de tipos e de valores citados na nota do erro.
- The
usedeclaration — Rust by Example (em inglês): exemplos curtos e executáveis de como importar e renomear.