Erro E0405 do Rust: cannot find trait in this scope (trait não encontrado)
O E0405 quer dizer que você citou um trait que o Rust não consegue ver daquele lugar. O caso clássico: você escreve impl Display for Point para que a sua struct possa ser impressa, mas nunca importou o Display. Um erro de digitação no nome do trait, ou um trait que mora em outro módulo, dá o mesmo erro. É um dos erros mais fáceis de corrigir, porque o rustc costuma mostrar exatamente a linha use de que você precisa. Ao contrário do E0412 (“cannot find type”, tipo não encontrado), que virou E0425 no Rust 1.93, este código não mudou: o rustc 1.97 continua mostrando E0405 para traits. Esta página faz parte do guia de erros do compilador.
A mensagem de erro
Seção intitulada “A mensagem de erro”error[E0405]: cannot find trait `Display` in this scope --> src/main.rs:6:6 |6 | impl Display for Point { // ❌ `Display` nunca foi importado | ^^^^^^^ not found in this scope |help: consider importing this trait |1 + use std::fmt::Display; |Em português: “não foi possível encontrar o trait Display neste escopo”. A ajuda sugere importar o trait com use std::fmt::Display;.
Este é o programa que gera o erro:
struct Point { x: i32, y: i32,}
impl Display for Point { // ❌ `Display` nunca foi importado 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);}O que significa
Seção intitulada “O que significa”O ^^^^^^^ aponta para Display na linha 6, com o rótulo “not found in this scope” (não encontrado neste escopo). O Rust olhou todos os traits visíveis dali: os que você definiu neste módulo, os que as suas linhas use trazem e o pequeno conjunto do prelude. Nenhum deles se chama Display.
O help: diz onde ele está: use std::fmt::Display;. O 1 + quer dizer “acrescente isto como uma nova linha 1”, no topo do arquivo.
Por que o Display está faltando, se o println! usa ele o tempo todo? O prelude, a lista de nomes que todo arquivo Rust ganha de graça, inclui Clone, Iterator, From, Default e outros traits do dia a dia, mas não Display, Error, Hash nem Write. Esses moram nos seus módulos (std::fmt, std::error, std::hash, std::io), e você os importa quando vai implementá-los.
É como uma receita que diz “use a panela Display”. O cozinheiro conhece as panelas que estão no fogão, mas essa está num armário, e a receita nunca disse em qual.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”O Rust nunca procura um nome na biblioteca padrão inteira, nem no seu projeto inteiro. Ele só olha o que está em escopo: os seus próprios itens, as suas linhas use e o prelude. Isso deixa os nomes previsíveis. Só na std existem vários traits chamados Write e Error, e um crate que você acrescentar depois pode trazer mais. Se o Rust escolhesse um por você, acrescentar uma dependência poderia mudar em silêncio o que o seu código significa.
Então você diz qual trait quer, uma vez, no topo do arquivo. A linha de ajuda faz a busca por você e sugere o trait que encontrou. Veja em Módulos como o use funciona, e em Traits comuns tudo sobre o Display.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Acrescente a linha use que o rustc sugere
Seção intitulada “Correção 1: Acrescente a linha use que o rustc sugere”Escolha esta quando a ajuda diz consider importing this trait (considere importar este trait), que é o que acontece na maioria das vezes. Copie a linha para o topo do arquivo:
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á em {}", Point { x: -1, y: 7 });}Saída:
(3, 4)Ferris está em (-1, 7)Se o rustc sugerir vários imports, leia antes de escolher. São traits diferentes que por acaso têm o mesmo nome, como std::fmt::Write e std::io::Write.
Correção 2: Importe o módulo e escreva fmt::Display
Seção intitulada “Correção 2: Importe o módulo e escreva fmt::Display”Escolha esta quando você está implementando Display, porque de qualquer jeito você precisa de Formatter e Result do mesmo módulo. Importe std::fmt uma vez e escreva fmt:: na frente dos três. É o estilo que você mais vai ver em código Rust de verdade:
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!("{} tem {} caracteres", label, label.len());}Saída:
(3, 4) tem 6 caracteresImplementar Display também te dá o .to_string() de graça. Você pode pular o use por completo e escrever impl std::fmt::Display for Point; isso funciona bem para um caso isolado.
Correção 3: Corrija a grafia do nome do trait
Seção intitulada “Correção 3: Corrija a grafia do nome do trait”Escolha esta quando o rustc diz a trait with a similar name exists (existe um trait com nome parecido). Nomes de traits diferenciam maiúsculas de minúsculas, então shape, Shap e Shape são três nomes diferentes:
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 { // ❌ erro de digitação: Shap | ^^^^ |help: a trait with a similar name exists |9 | impl Shape for Square { // ❌ erro de digitação: Shap | +O rustc mostra onde o trait Shape, de nome parecido, foi definido, e sugere a grafia certa.
O programa com erro:
trait Shape { fn area(&self) -> f64;}
struct Square { side: f64,}
impl Shap for Square { // ❌ erro de digitação: Shap fn area(&self) -> f64 { self.side * self.side }}
fn main() { let s = Square { side: 3.0 }; println!("{}", s.area());}O + embaixo da linha 9 mostra a letra que falta. Acrescente-a:
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());}Saída:
9Se não houver nenhum nome parecido nem sugestão de import, o trait ainda não existe. Defina-o antes com trait Shape { ... }. Veja Traits.
Correção 4: Importe o seu próprio trait do módulo dele
Seção intitulada “Correção 4: Importe o seu próprio trait do módulo dele”Escolha esta quando o trait é seu, mas mora em outro módulo. Cada módulo tem o seu próprio escopo, então um trait em mod shapes não fica visível no topo do main.rs até você importá-lo:
error[E0405]: cannot find trait `Shape` in this scope --> src/main.rs:11:6 |11 | impl Shape for Square { // ❌ `Shape` mora em `mod shapes` | ^^^^^ not found in this scope |help: consider importing this trait | 1 + use crate::shapes::Shape; |O rustc não encontra Shape neste escopo e sugere importar crate::shapes::Shape.
O programa com erro:
mod shapes { pub trait Shape { fn area(&self) -> f64; }}
struct Square { side: f64,}
impl Shape for Square { // ❌ `Shape` mora em `mod shapes` fn area(&self) -> f64 { self.side * self.side }}
fn main() { println!("{}", Square { side: 2.0 }.area());}Acrescente a linha use e confira se o trait é pub. Sem pub, o próprio import falha com E0603, “trait is private” (o trait é 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());}Saída:
4O mesmo vale para traits de crates: impl Serialize for User precisa antes de use serde::Serialize;. Veja Módulos.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”Box<dyn Error> no main ou numa função auxiliar. fn run() -> Result<(), Box<dyn Error>> sem import dá cannot find trait `Error` in this scope, com help: consider importing this trait e use std::error::Error;. Correção: acrescente essa linha, ou escreva Box<dyn std::error::Error>. Veja Erros personalizados.
Trait bounds em genéricos. fn print_all<T: Display>(items: &[T]) dá o mesmo E0405 para Display, apontando para o bound (a restrição). Correção: use std::fmt::Display;. Veja Genéricos.
O Debug dá outro código. impl Debug for Point ou T: Debug sem import não dá E0405, e sim E0404: expected trait, found derive macro `Debug` (era esperado um trait, foi encontrada a macro derive Debug). O prelude tem a macro #[derive(Debug)], mas não o trait Debug. Correção: use std::fmt::Debug; (o rustc sugere), ou só #[derive(Debug)] se você não precisa de um formato próprio.
Erros relacionados
Seção intitulada “Erros relacionados”- E0425: não foi encontrado um valor, uma função ou (desde o Rust 1.93) um tipo neste escopo.
- E0412: o código antigo para “cannot find type”, hoje mostrado como E0425.
- E0433: não foi encontrada a primeira parte de um caminho, como
fmt::Displaysemuse std::fmt;. - E0599: método não encontrado, muitas vezes porque o trait que fornece o método não foi importado.
- E0277: o trait foi encontrado, mas o seu tipo não o implementa.
- E0404: um nome que existe, mas não é um trait (como a macro
Debug), mostrado acima. - 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ê escreve impl Display for Invoice e recebe E0405. O que está faltando?
2. Qual destes traits você pode usar sem nenhuma linha use?
3. O seu trait Shape está definido em mod shapes, e o impl Shape for Square está no main.rs. Do que você precisa?
Pontuação: 0 / 3
Para saber mais
Seção intitulada “Para saber mais”- E0405 — Rust error codes index (em inglês): a explicação oficial, com as duas correções: importar o trait ou defini-lo.
- Implementing a Trait on a Type — The Rust Book (em inglês): como
impl Trait for Typefunciona, e por que o trait precisa estar em escopo. std::fmt::Display— documentação da biblioteca padrão (em inglês): o trait desta página, com um exemplo completo deimpl fmt::Display.- Display — Rust by Example (em inglês): como implementar
Displaypasso a passo, comuse std::fmt;. std::prelude— documentação da biblioteca padrão (em inglês): a lista de traits e tipos que você pode usar sem importar.