Error E0255 de Rust: the name is defined multiple times (import contra tu tipo)
E0255 significa que una línea use y algo que definiste tú tienen el mismo nombre. El caso clásico: importas std::io::Error al principio del archivo y más abajo escribes tu propio enum Error. Rust no puede dejar que un nombre signifique dos cosas, así que se detiene. Es un error muy habitual cuando empiezas a escribir tus propios tipos de error, y se arregla con una línea corta. A diferencia de E0412, este código no ha cambiado en las versiones recientes: rustc 1.97 lo sigue mostrando como E0255. Forma parte de la guía de errores del compilador.
El mensaje de error
Sección titulada «El mensaje de error»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; | ^^^^^^^^^^^^^^“The name Error is defined multiple times” quiere decir “el nombre Error está definido varias veces”. Abajo te explicamos cada parte del mensaje.
Este es el programa que lo produce:
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!("el nombre está bien"), Err(Error::EmptyName) => println!("el nombre está vacío"), Err(Error::TooLong(n)) => println!("el nombre tiene {} letras, el máximo es 10", n), }}Qué significa
Sección titulada «Qué significa»rustc señala tres cosas:
- La línea
---(línea 1): “previous import of the typeErrorhere” (aquí está el import anterior del tipoError). La líneauseya puso un nombreErroren este módulo. - La línea
^^^(línea 3): “Errorredefined here” (aquí se vuelve a definirError). Tu propioenum Errorintenta quedarse con el mismo nombre. - El
help:te ofrece una salida: darle al import otro nombre local conas.
El warning: unused import (import sin usar) que aparece debajo es una pista útil. Significa que nada en tu código usa de verdad std::io::Error (cada Error de este programa se refiere a tu enum). En ese caso puedes simplemente borrar la línea 1. Si de verdad necesitas los dos, sigue leyendo.
La nota habla del type namespace (espacio de nombres de tipos). Los tipos, los traits y los módulos comparten una lista de nombres; las funciones, las constantes y los statics comparten otra. Así que use std::mem::swap; junto con tu propia fn swap es el mismo error, pero en el “value namespace” (espacio de nombres de valores).
Piensa en una clase con dos alumnos que se llaman Álex. La profesora ya no puede decir solo “Álex”. Alguien necesita un apodo, como “Álex B.”, y eso es justo lo que as le da a un import.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»Un nombre dentro de un módulo apunta a exactamente un elemento. Cuando Rust lee Error::EmptyName en la línea 10, tiene que saber a qué Error te refieres, y se niega a adivinar. Si eligiera tu enum sin avisar, tu línea use no haría nada; si eligiera io::Error, no podrías llegar a tu enum. En los dos casos, una elección silenciosa escondería un error.
Por eso E0255 es hermano de E0428 (dos elementos tuyos con un mismo nombre) y de E0252 (dos líneas use con un mismo nombre). La regla es la misma: un nombre, una cosa, en cada módulo. Mira use: acortar rutas largas para ver cómo funciona use.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Renombra el import con as
Sección titulada «Solución 1: Renombra el import con as»Elige esta cuando necesitas los dos tipos en el mismo archivo, algo bastante común: tu propio Error para las reglas de tu programa, e io::Error para archivos y red. Dale al import un apodo que diga de dónde viene. IoError se lee mejor que el OtherError provisional de 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, "ese nombre está reservado")); } Ok(())}
fn main() { println!("{:?}", check_name("Ferris")); println!("{:?}", check_name("")); println!("{:?}", check_name("Ferris the Crab")); match save_name("root") { Ok(()) => println!("guardado"), Err(e) => println!("error de E/S: {}", e), }}Salida:
Ok(())Err(EmptyName)Err(TooLong(15))error de E/S: ese nombre está reservadoas solo cambia el nombre en este archivo. En cualquier otro sitio, el tipo sigue siendo std::io::Error. (Dejamos "Ferris the Crab" en inglés porque el ejemplo cuenta sus letras con .len().)
Solución 2: Importa el módulo, no el tipo
Sección titulada «Solución 2: Importa el módulo, no el tipo»Elige esta cuando prefieres que cada Error muestre de dónde viene cada vez que lo usas. Importa el módulo padre con use std::io; y escribe io::Error. Tu propio Error se queda con el nombre corto. Muchos programadores de Rust prefieren este estilo para tipos con nombres tan comunes como Error y 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, "nombre reservado")); } Ok(())}
fn main() { if let Err(Error::EmptyName) = check_name("") { println!("el nombre está vacío"); } if let Err(e) = save_name("root") { println!("error de E/S: {}", e); }}Salida:
el nombre está vacíoerror de E/S: nombre reservadoSolución 3: Cambia el nombre de tu propio elemento
Sección titulada «Solución 3: Cambia el nombre de tu propio elemento»Elige esta cuando tu tipo se va a usar en muchos archivos, o lo van a usar otras personas. Un nombre concreto como NameError o AppError es más claro que un segundo Error, y la línea use se puede quedar 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("el disco está lleno"); println!("{}", disk);}Salida:
Err(TooLong(15))el disco está llenoEn proyectos más grandes, el crate thiserror hace que estos enums de error sean mucho más cortos de escribir. Mira Errores personalizados.
Solución 4: Borra el import que no usas
Sección titulada «Solución 4: Borra el import que no usas»Elige esta cuando rustc también muestra warning: unused import, como en el error de arriba. El import es un resto de código anterior, o lo añadió tu editor. Quita la línea, y el programa del principio de esta página funciona tal cual:
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!("el nombre está bien"), Err(Error::EmptyName) => println!("el nombre está vacío"), Err(Error::TooLong(n)) => println!("el nombre tiene {} letras, el máximo es 10", n), }}Salida:
el nombre está vacíoDónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»Una función tuya con un nombre de std. use std::mem::swap; junto con fn swap(a: &mut i32, b: &mut i32) da E0255 con “previous import of the value swap here” y la nota “value namespace”. Solución: llama a la tuya swap_values, o quita el import si querías escribir la tuya.
Copiar y pegar entre módulos. Mueves struct User a mod models, añades use models::User; arriba, pero te olvidas de borrar el struct User antiguo de main.rs. Solución: borra la copia antigua, para que User signifique solo el de models.
Un trait con un nombre de std. use std::fmt::Display; y tu propio trait Display chocan igual (“previous import of the trait Display”). Solución: cambia el nombre de tu trait (Describe, Render), o escribe use std::fmt; y fmt::Display.
Conviene saberlo: un import glob (con comodín) como use std::io::*; nunca causa E0255. Tus propios elementos ganan sin hacer ruido a los nombres que entran por un *. Es práctico, pero también puede esconder qué Error estás usando, así que los imports explícitos suelen ser más claros.
Errores relacionados
Sección titulada «Errores relacionados»- E0252: dos líneas
usetraen el mismo nombre, comofmt::Resulteio::Result. - E0428: dos elementos tuyos comparten nombre, a menudo al intentar sobrecargar una función.
- E0592: dos métodos con el mismo nombre en un bloque
impl. - E0432: la propia línea
useapunta a algo que no existe. - E0425: el problema contrario: un nombre que no está definido en absoluto donde lo usas.
- Todos los errores del compilador: la lista completa de páginas de errores.
Comprueba lo que aprendiste
Sección titulada «Comprueba lo que aprendiste»Comprueba lo aprendido
1. Tu archivo empieza con use std::fmt::Result; y más abajo define enum Result { Pass, Fail }. ¿Qué error obtienes?
2. Necesitas std::io::Error y tu propio enum Error en el mismo archivo. ¿Cuál es una solución limpia?
3. rustc muestra E0255 y también warning: unused import: std::io::Error. ¿Qué te dice el aviso?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0255 — Rust error codes index (en inglés): la explicación oficial, con un
use bar::foo;que choca confn foo, resuelto conaso con la ruta del módulo padre. - Providing New Names with the
asKeyword — El libro de Rust (en inglés): cómoasrenombra un import, con los dos tiposResult. También existe una traducción al español de la comunidad del libro. - Use declarations — The Rust Reference (en inglés): todas las formas de
use, incluidosas, los grupos y los globs. - Namespaces — The Rust Reference (en inglés): los espacios de nombres de tipos y de valores de la nota del error.
- The
usedeclaration — Rust by Example (en inglés): ejemplos cortos y ejecutables de importar y renombrar.