Pular para o conteúdo

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.

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 ^^^^^^^ 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.

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.

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)
▶ Experimente você mesmo

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 caracteres
▶ Experimente você mesmo

Implementar 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.

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:

9
▶ Experimente você mesmo

Se 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:

4
▶ Experimente você mesmo

O mesmo vale para traits de crates: impl Serialize for User precisa antes de use serde::Serialize;. Veja Módulos.

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.

  • 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::Display sem use 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

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