Erro E0252 do Rust: the name is defined multiple times (dois imports)
O E0252 quer dizer que duas linhas use trazem o mesmo nome. O caso de livro é use std::fmt::Result; mais use std::io::Result;: dois tipos diferentes, os dois chamados Result. Outros exemplos são fmt::Error e io::Error, ou os dois traits Write. É um erro muito comum e fácil de corrigir, normalmente mudando uma ou duas linhas use. O rustc 1.97 continua mostrando esse erro com o seu próprio código, E0252. Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0252]: the name `Result` is defined multiple times --> src/main.rs:2:5 |1 | use std::fmt::Result; | ---------------- previous import of the type `Result` here2 | use std::io::Result; // ❌ um segundo `Result` | ^^^^^^^^^^^^^^^ `Result` reimported here | = note: `Result` must be defined only once in the type namespace of this modulehelp: you can use `as` to change the binding name of the import |2 | use std::io::Result as OtherResult; // ❌ um segundo `Result` | ++++++++++++++Em português: “o nome Result foi definido várias vezes”. O rustc mostra o primeiro import, o segundo (“importado de novo aqui”), uma nota sobre o namespace de tipos e uma sugestão com as.
Este é o programa que gera o erro:
use std::fmt::Result;use std::io::Result; // ❌ um segundo `Result`
struct Temperature { celsius: i32,}
impl std::fmt::Display for Temperature { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result { write!(f, "{} °C", self.celsius) }}
fn parse_temperature(text: &str) -> Result<Temperature> { match text.trim().parse() { Ok(celsius) => Ok(Temperature { celsius }), Err(_) => Err(std::io::Error::other("não é um número")), }}
fn main() { match parse_temperature("21") { Ok(t) => println!("{}", t), Err(e) => println!("erro: {}", e), }}O rustc mostra mais quatro erros depois deste: E0107 (“type alias takes 0 generic arguments”, o alias de tipo recebe 0 argumentos genéricos), dois E0308 de tipos incompatíveis e um E0277. Não vá atrás deles. O Rust ficou com o primeiro import, então todo Result no arquivo agora significa fmt::Result, e parse_temperature deixa de fazer sentido. Corrija o E0252 e todos eles somem.
O que significa
Seção intitulada “O que significa”O rustc aponta para duas linhas use:
- A linha
---(linha 1): “previous import of the typeResulthere” (import anterior do tipoResultaqui). Esta veio primeiro, então é a que o Rust mantém. - A linha
^^^(linha 2): “Resultreimported here” (Resultimportado de novo aqui). O segundo import tenta ocupar o mesmo nome. - O
help:sugere renomear o segundo import comas.
std::fmt::Result e std::io::Result são mesmo diferentes. fmt::Result é um simples Result<(), fmt::Error>, usado por Display e Debug. io::Result<T> é Result<T, io::Error>, usado por arquivos e pela rede. Mesmo nome, trabalhos diferentes.
É como salvar dois contatos como “Mãe” no celular: a sua mãe e a sua sogra. Quando você toca em “Mãe”, o celular precisa saber para qual das duas ligar. Você acrescenta uma palavra a um deles, ou salva como “Mãe (Ana)” e “Mãe (Lia)”.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”Dentro de um módulo, cada nome aponta para exatamente um item. Uma linha use não copia nada; ela acrescenta um nome curto para um item que mora em outro lugar. Duas linhas use que acrescentam o mesmo nome curto deixariam ambíguo todo Result que viesse depois, então o Rust para no import em vez de tentar adivinhar em cada uso.
O E0252 é um de três irmãos com a mesma primeira linha: o E0255 é uma linha use contra um item seu, e o E0428 são dois itens seus. A regra por trás dos três é “um nome, uma coisa, por módulo”. Veja Módulos.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Importe os módulos e escreva fmt:: e io::
Seção intitulada “Correção 1: Importe os módulos e escreva fmt:: e io::”Escolha esta na maioria das vezes, e sempre para Result e Error. Importe os módulos pai e escreva o nome do módulo na frente. Agora cada uso diz qual Result ele é. O Rust Book recomenda esse estilo exatamente para este caso:
use std::fmt;use std::io;
struct Temperature { celsius: i32,}
impl fmt::Display for Temperature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} °C", self.celsius) }}
fn parse_temperature(text: &str) -> io::Result<Temperature> { match text.trim().parse() { Ok(celsius) => Ok(Temperature { celsius }), Err(_) => Err(io::Error::other("não é um número")), }}
fn main() { for input in ["21", " -4 ", "quente"] { match parse_temperature(input) { Ok(t) => println!("{}", t), Err(e) => println!("erro: {}", e), } }}Saída:
21 °C-4 °Cerro: não é um númeroBônus: o Result<T, E> comum do prelude continua livre para usar, sem nenhum import.
Correção 2: Renomeie um dos imports com as
Seção intitulada “Correção 2: Renomeie um dos imports com as”Escolha esta quando você usa muito um dos dois tipos e quer um nome curto para ele. Esta é a sugestão do rustc. Escolha um nome que diga de onde ele vem, como IoResult, em vez de OtherResult:
use std::fmt::Result;use std::io::Result as IoResult;
struct Temperature { celsius: i32,}
impl std::fmt::Display for Temperature { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result { write!(f, "{} °C", self.celsius) }}
fn parse_temperature(text: &str) -> IoResult<Temperature> { match text.trim().parse() { Ok(celsius) => Ok(Temperature { celsius }), Err(_) => Err(std::io::Error::other("não é um número")), }}
fn main() { match parse_temperature("21") { Ok(t) => println!("{}", t), Err(e) => println!("erro: {}", e), }}Saída:
21 °CUm Result simples que na verdade significa fmt::Result pode surpreender quem ler o código depois, então a Correção 1 costuma ser mais clara. O as brilha com nomes longos, como use std::collections::BTreeMap as Map;.
Correção 3: Importe um trait com as _
Seção intitulada “Correção 3: Importe um trait com as _”Escolha esta para traits que você só importa para chamar os métodos deles. Os dois traits Write são o caso clássico: o fmt::Write deixa você usar write! numa String, e o io::Write deixa você usar write! no stdout ou num arquivo. Importar os dois pelo nome dá conflito:
error[E0252]: the name `Write` is defined multiple times --> src/main.rs:2:5 |1 | use std::fmt::Write; | --------------- previous import of the trait `Write` here2 | use std::io::Write; // ❌ um segundo `Write` | ^^^^^^^^^^^^^^ `Write` reimported here | = note: `Write` must be defined only once in the type namespace of this modulehelp: you can use `as` to change the binding name of the import |2 | use std::io::Write as OtherWrite; // ❌ um segundo `Write` | +++++++++++++É a mesma mensagem de antes, agora para o trait Write: o primeiro import, o segundo e a sugestão de renomear com as.
O programa com erro:
use std::fmt::Write;use std::io::Write; // ❌ um segundo `Write`
fn main() { let mut report = String::new(); write!(report, "{} testes passaram", 12).unwrap();
let mut out = std::io::stdout(); writeln!(out, "{}", report).unwrap();}Aqui você nunca escreve Write; você só precisa dos métodos dele. O as _ importa um trait sem dar um nome a ele, então nada pode entrar em conflito, e os dois conjuntos de métodos continuam funcionando:
use std::fmt::Write as _;use std::io::Write as _;
fn main() { let mut report = String::new(); write!(report, "{} testes passaram", 12).unwrap();
let mut out = std::io::stdout(); writeln!(out, "{}", report).unwrap();}Saída:
12 testes passaramSe você precisa dar nome a um deles, por exemplo em fn log(w: &mut impl io::Write), combine isso com a Correção 1: use std::io; e escreva io::Write. Veja Traits.
Correção 4: Tire um import repetido do mesmo item
Seção intitulada “Correção 4: Tire um import repetido do mesmo item”Escolha esta quando as duas linhas importam exatamente a mesma coisa, o que acontece muito depois de juntar código ou quando o seu editor acrescenta um import que você já tinha:
error[E0252]: the name `HashMap` is defined multiple times --> src/main.rs:2:24 |1 | use std::collections::HashMap; | ------------------------- previous import of the type `HashMap` here2 | use std::collections::{HashMap, HashSet}; // ❌ `HashMap` de novo | ^^^^^^^-- | | | `HashMap` reimported here | help: remove unnecessary importO rustc mostra o primeiro import de HashMap, o segundo e a ajuda “remove unnecessary import” (tire o import desnecessário).
O programa com erro:
use std::collections::HashMap;use std::collections::{HashMap, HashSet}; // ❌ `HashMap` de novo
fn main() { let mut stock: HashMap<&str, u32> = HashMap::new(); stock.insert("maçãs", 3);
let mut sold_out: HashSet<&str> = HashSet::new(); sold_out.insert("peras");
println!("maçãs: {}, esgotados: {}", stock["maçãs"], sold_out.len());}Repare que a ajuda é diferente: nada de as, só “remove unnecessary import”. Fique com uma linha só:
use std::collections::{HashMap, HashSet};
fn main() { let mut stock: HashMap<&str, u32> = HashMap::new(); stock.insert("maçãs", 3);
let mut sold_out: HashSet<&str> = HashSet::new(); sold_out.insert("peras");
println!("maçãs: {}, esgotados: {}", stock["maçãs"], sold_out.len());}Saída:
maçãs: 3, esgotados: 1Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Error vindo de dois lugares. use std::fmt::Error; e use std::io::Error;, ou use std::error::Error; junto com use anyhow::Error;. Correção: use std::io; e escreva io::Error, ou use anyhow::Error as AnyError;. Veja anyhow e thiserror.
Dois crates com o mesmo nome de tipo. use chrono::Duration; e use std::time::Duration; são uma dupla comum em projetos que lidam com datas. Correção: deixe um com o nome curto e escreva o módulo do outro, como chrono::Duration. Veja Datas e horas.
Imports glob. use std::fmt::*; mais use std::io::*; não dá E0252 nas linhas use. O problema aparece depois, no primeiro Result, como um erro sem código: error: `Result` is ambiguous (Result é ambíguo). Correção: importe explicitamente os nomes de que você precisa, como na Correção 1.
Erros relacionados
Seção intitulada “Erros relacionados”- E0255: uma linha
usese choca com uma struct, enum ou função sua de mesmo nome. - E0428: dois itens seus têm o mesmo nome, muitas vezes por tentar sobrecarregar uma função.
- E0432: import não resolvido, quando a linha
useaponta para algo que não existe. - E0034: dois traits em escopo dão a um tipo métodos com o mesmo nome.
- E0308: tipos incompatíveis, um dos erros que aparecem em seguida depois de um conflito de
Result. - 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. Você precisa de fmt::Result e io::Result no mesmo arquivo. Quais imports são a escolha limpa de costume?
2. Você precisa dos métodos de std::fmt::Write e de std::io::Write, mas nunca escreve o nome dos traits. O que funciona?
3. O rustc diz que HashMap is reimported here e sugere remove unnecessary import. O que aconteceu?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0252 — Rust error codes index (em inglês): a explicação oficial, com a correção usando
ase a correção usando o caminho do módulo. - Providing New Names with the
asKeyword — The Rust Book (em inglês): o exemplo defmt::Resulteio::Result, resolvido de dois jeitos. - Underscore imports — The Rust Reference (em inglês): como
use Trait as _;traz os métodos sem um nome. - The
usedeclaration — Rust by Example (em inglês): exemplos curtos e executáveis de como importar e renomear. - Namespaces — The Rust Reference (em inglês): por que traits e tipos dividem o namespace de tipos citado na nota do erro.