Error E0405 de Rust: cannot find trait in this scope (trait no encontrado)
E0405 significa que nombraste un trait que Rust no ve desde ese sitio. El caso clásico: escribes impl Display for Point para que tu struct se pueda imprimir, pero nunca importaste Display. Una errata en el nombre del trait, o un trait que vive en otro módulo, dan el mismo error. Es uno de los errores más fáciles de arreglar, porque rustc normalmente te muestra la línea use exacta que necesitas. A diferencia de E0412 (“cannot find type”), que pasó a ser E0425 en Rust 1.93, este código no ha cambiado: rustc 1.97 sigue mostrando E0405 para los traits. Forma parte de la guía de errores del compilador.
El mensaje de error
Sección titulada «El mensaje de error»error[E0405]: cannot find trait `Display` in this scope --> src/main.rs:6:6 |6 | impl Display for Point { // ❌ `Display` was never imported | ^^^^^^^ not found in this scope |help: consider importing this trait |1 + use std::fmt::Display; |“Cannot find trait Display in this scope” quiere decir “no se encuentra el trait Display en este ámbito”, y el help te sugiere importarlo.
Este es el programa que lo produce:
struct Point { x: i32, y: i32,}
impl Display for Point { // ❌ `Display` was never imported fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{}", p);}Qué significa
Sección titulada «Qué significa»El ^^^^^^^ señala Display en la línea 6, con la etiqueta “not found in this scope” (no encontrado en este ámbito). Rust miró todos los traits visibles desde ahí: los que definiste en este módulo, los que traen tus líneas use y el pequeño grupo del prelude (los nombres que vienen incluidos). Ninguno se llama Display.
El help: te dice dónde está: use std::fmt::Display;. El 1 + significa “añade esto como una nueva línea 1”, al principio del archivo.
¿Por qué falta Display si println! lo usa todo el rato? El prelude, la lista de nombres que cada archivo de Rust recibe gratis, incluye Clone, Iterator, From, Default y otros traits de todos los días, pero no Display, Error, Hash ni Write. Esos viven en sus módulos (std::fmt, std::error, std::hash, std::io), y los importas cuando los implementas.
Es como una receta que dice “usa la sartén Display”. El cocinero conoce las sartenes que están en el fuego, pero esta está en un armario, y la receta nunca dijo en cuál.
Por qué Rust hace esto
Sección titulada «Por qué Rust hace esto»Rust nunca busca un nombre en toda la biblioteca estándar, ni en todo tu proyecto. Solo mira lo que está en el ámbito: tus propios elementos, tus líneas use y el prelude. Así los nombres son predecibles. Solo en std hay varios traits que se llaman Write y Error, y un crate que añadas más adelante podría traer más. Si Rust eligiera uno por ti, añadir una dependencia podría cambiar sin avisar lo que significa tu código.
Así que tú dices qué trait quieres, una vez, al principio del archivo. La línea del help hace la búsqueda por ti y te sugiere el trait que encontró. Mira use: acortar rutas largas para ver cómo funciona use, y Traits comunes para Display.
Cómo solucionarlo
Sección titulada «Cómo solucionarlo»Solución 1: Añade la línea use que sugiere rustc
Sección titulada «Solución 1: Añade la línea use que sugiere rustc»Elige esta cuando el help dice consider importing this trait (considera importar este trait), que es casi siempre. Copia la línea al principio del archivo:
use std::fmt::Display;
struct Point { x: i32, y: i32,}
impl Display for Point { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; println!("{}", p); println!("Ferris está en {}", Point { x: -1, y: 7 });}Salida:
(3, 4)Ferris está en (-1, 7)Si rustc sugiere varios imports, léelos antes de elegir. Son traits distintos que comparten nombre por casualidad, como std::fmt::Write y std::io::Write.
Solución 2: Importa el módulo y escribe fmt::Display
Sección titulada «Solución 2: Importa el módulo y escribe fmt::Display»Elige esta cuando estás implementando Display, porque de todas formas necesitas Formatter y Result del mismo módulo. Importa std::fmt una vez y escribe fmt:: delante de los tres. Es el estilo que más verás en código Rust real:
use std::fmt;
struct Point { x: i32, y: i32,}
impl fmt::Display for Point { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({}, {})", self.x, self.y) }}
fn main() { let p = Point { x: 3, y: 4 }; let label = p.to_string(); println!("{} tiene {} caracteres", label, label.len());}Salida:
(3, 4) tiene 6 caracteresImplementar Display también te da .to_string() gratis. Puedes saltarte el use del todo y escribir impl std::fmt::Display for Point; está bien para un caso suelto.
Solución 3: Corrige cómo se escribe el nombre del trait
Sección titulada «Solución 3: Corrige cómo se escribe el nombre del trait»Elige esta cuando rustc dice a trait with a similar name exists (existe un trait con un nombre parecido). Los nombres de los traits distinguen mayúsculas y minúsculas, así que shape, Shap y Shape son tres nombres distintos:
error[E0405]: cannot find trait `Shap` in this scope --> src/main.rs:9:6 |1 | trait Shape { | ----------- similarly named trait `Shape` defined here...9 | impl Shap for Square { // ❌ typo: Shap | ^^^^ |help: a trait with a similar name exists |9 | impl Shape for Square { // ❌ typo: Shap | +La etiqueta de la línea 1 señala el trait Shape de nombre parecido. El programa con el error:
trait Shape { fn area(&self) -> f64;}
struct Square { side: f64,}
impl Shap for Square { // ❌ typo: Shap fn area(&self) -> f64 { self.side * self.side }}
fn main() { let s = Square { side: 3.0 }; println!("{}", s.area());}El + debajo de la línea 9 muestra la letra que falta. Añádela:
trait Shape { fn area(&self) -> f64;}
struct Square { side: f64,}
impl Shape for Square { fn area(&self) -> f64 { self.side * self.side }}
fn main() { let s = Square { side: 3.0 }; println!("{}", s.area());}Salida:
9Si no hay ningún nombre parecido ni ninguna sugerencia de import, el trait todavía no existe. Defínelo primero con trait Shape { ... }. Mira Definir un trait.
Solución 4: Importa tu propio trait desde su módulo
Sección titulada «Solución 4: Importa tu propio trait desde su módulo»Elige esta cuando el trait es tuyo pero vive en otro módulo. Cada módulo tiene su propio ámbito, así que un trait de mod shapes no se ve al principio de main.rs hasta que lo importas:
error[E0405]: cannot find trait `Shape` in this scope --> src/main.rs:11:6 |11 | impl Shape for Square { // ❌ `Shape` lives in `mod shapes` | ^^^^^ not found in this scope |help: consider importing this trait | 1 + use crate::shapes::Shape; |El programa con el error:
mod shapes { pub trait Shape { fn area(&self) -> f64; }}
struct Square { side: f64,}
impl Shape for Square { // ❌ `Shape` lives in `mod shapes` fn area(&self) -> f64 { self.side * self.side }}
fn main() { println!("{}", Square { side: 2.0 }.area());}Añade la línea use y comprueba que el trait es pub. Sin pub, el propio import falla con E0603, “trait is private” (el trait es privado):
mod shapes { pub trait Shape { fn area(&self) -> f64; }}
use crate::shapes::Shape;
struct Square { side: f64,}
impl Shape for Square { fn area(&self) -> f64 { self.side * self.side }}
fn main() { println!("{}", Square { side: 2.0 }.area());}Salida:
4Lo mismo pasa con los traits de los crates: impl Serialize for User necesita antes use serde::Serialize;. Mira Todo es privado por defecto.
Dónde lo verás normalmente
Sección titulada «Dónde lo verás normalmente»Box<dyn Error> en main o en una función auxiliar. fn run() -> Result<(), Box<dyn Error>> sin import da cannot find trait `Error` in this scope, con help: consider importing this trait y use std::error::Error;. Solución: añade esa línea, o escribe Box<dyn std::error::Error>. Mira Errores personalizados.
Trait bounds (restricciones de traits) en genéricos. fn print_all<T: Display>(items: &[T]) da el mismo E0405 para Display, señalando la restricción. Solución: use std::fmt::Display;. Mira Genéricos.
Debug da otro código. impl Debug for Point o T: Debug sin import no es E0405 sino E0404: expected trait, found derive macro `Debug` (se esperaba un trait, se encontró la macro derive Debug). El prelude tiene la macro #[derive(Debug)], pero no el trait Debug. Solución: use std::fmt::Debug; (rustc te lo sugiere), o simplemente #[derive(Debug)] si no necesitas un formato propio.
Errores relacionados
Sección titulada «Errores relacionados»- E0425: no se encuentra un valor, una función o (desde Rust 1.93) un tipo en este ámbito.
- E0412: el código antiguo de “cannot find type”, que ahora se muestra como E0425.
- E0433: no se encuentra la primera parte de una ruta, como
fmt::Displaysinuse std::fmt;. - E0599: no se encuentra un método, a menudo porque el trait que lo aporta no está importado.
- E0277: el trait sí se encontró, pero tu tipo no lo implementa.
- E0404: un nombre que existe pero no es un trait (como la macro
Debug), como viste arriba. - 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. Escribes impl Display for Invoice y obtienes E0405. ¿Qué falta?
2. ¿Cuál de estos traits puedes usar sin ninguna línea use?
3. Tu trait Shape está definido en mod shapes, y impl Shape for Square está en main.rs. ¿Qué necesitas?
Puntuación: 0 / 3
Para leer más
Sección titulada «Para leer más»- E0405 — Rust error codes index (en inglés): la explicación oficial, con las dos soluciones: importar el trait o definirlo.
- Implementing a Trait on a Type — El libro de Rust (en inglés): cómo funciona
impl Trait for Type, y por qué el trait tiene que estar en el ámbito. También existe una traducción al español de la comunidad del libro. std::fmt::Display— documentación de la biblioteca estándar (en inglés): el trait de esta página, con un ejemplo completo deimpl fmt::Display.- Display — Rust by Example (en inglés): implementar
Displaypaso a paso, conuse std::fmt;. std::prelude— documentación de la biblioteca estándar (en inglés): la lista de traits y tipos que puedes usar sin importarlos.