Pular para o conteúdo

Erro E0412 do Rust: cannot find type in this scope (tipo não encontrado)

O E0412 quer dizer que você escreveu um nome de tipo que o Rust não enxerga naquele ponto, por exemplo numa assinatura de função como fn print_invoice(inv: &Invoce). É um erro muito comum e fácil de resolver: um erro de digitação, uma linha use que faltou, ou um genérico <T> que você esqueceu de declarar. Uma coisa pode confundir você logo de cara: desde o Rust 1.93, o compilador mostra este erro como E0425, com a mesma mensagem, cannot find type. Esta página trata dos dois, e faz parte do guia de erros do compilador.

É isto que o Rust 1.93 e as versões mais novas mostram (o compilador atual é o 1.97):

error[E0425]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) { // ❌ erro de digitação: Invoce
| ^^^^^^
|
help: a struct with a similar name exists
|
2 | fn print_invoice(inv: &Invoice) { // ❌ erro de digitação: Invoce
| +

E este é o mesmo programa no Rust 1.92 ou mais antigo, a versão com que foi escrita a maioria dos posts de blog e das respostas do Stack Overflow:

error[E0412]: cannot find type `Invoce` in this scope
--> src/main.rs:2:24
|
1 | struct Invoice { total: u32 }
| -------------- similarly named struct `Invoice` defined here
2 | fn print_invoice(inv: &Invoce) {
| ^^^^^^ help: a struct with a similar name exists: `Invoice`

Em português: “não foi encontrado o tipo Invoce neste escopo”. O rustc mostra onde a struct de nome parecido, Invoice, foi definida, e a ajuda diz “existe uma struct com um nome parecido”.

Este é o programa que gera os dois:

struct Invoice { total: u32 }
fn print_invoice(inv: &Invoce) { // ❌ erro de digitação: Invoce
println!("{}", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

A página oficial do E0412 (em inglês) agora começa com “this error code is no longer emitted by the compiler” (este código de erro não é mais emitido pelo compilador). O problema não sumiu, só passou para o E0425, que também trata de variáveis e funções não encontradas. Tudo o que vem abaixo funciona igual para os dois códigos.

O ^^^^^^ aponta para Invoce na assinatura. Para conferir esta função, o Rust precisa saber o que é um Invoce: qual o tamanho dele, quais campos ele tem. Ele olhou todos os tipos visíveis a partir da linha 2 (as suas próprias structs e enums, as suas linhas use e o prelude) e não encontrou nada com esse nome.

A linha help: diz em qual situação você está:

  • “a struct with a similar name exists” (existe uma struct com um nome parecido): é erro de digitação. O + mostra a letra que faltou.
  • “consider importing this struct” (considere importar esta struct): o tipo existe em outro lugar, e você precisa de uma linha use.
  • “you might be missing a type parameter” (talvez esteja faltando um parâmetro de tipo): você usou um genérico T sem declarar <T>.
  • nenhuma ajuda: o tipo ainda não existe. Você ainda não o escreveu, ou ele está num arquivo que o Rust não conhece.

É como uma receita que diz “acrescente 200 g de Invoce”. O cozinheiro sabe o que é farinha e açúcar, mas não sabe o que é “Invoce”, então para antes mesmo de começar.

O Rust confere a assinatura de cada função antes de o programa rodar. Cada parâmetro e cada tipo de retorno precisa ser um tipo real e conhecido, porque o Rust usa essa informação para decidir quanta memória o valor precisa e quais métodos e campos ele tem. Um nome que ele não encontra não é algo em que ele esteja disposto a chutar.

Só um pequeno grupo de nomes de tipo fica visível em todo lugar sem use: o prelude, com String, Vec, Option, Result, Box e mais alguns. Todo o resto precisa de uma definição sua, de uma linha use ou de um caminho completo como std::num::ParseIntError. Veja Módulos para entender como funcionam os caminhos e o use.

Por que o código mudou? Desde o Rust 1.93, o rustc mostra um tipo não encontrado como E0425, o mesmo código que ele já usava para uma variável ou função não encontrada. A mensagem continua dizendo type, então você sempre consegue saber que tipo de nome sumiu.

Escolha esta quando o rustc disser que existe um nome parecido, ou não der nenhuma ajuda. Nomes de tipo diferenciam maiúsculas de minúsculas: invoice, Invoce e Invoice são três nomes diferentes. Se não houver nenhum nome parecido, escreva a struct ou o enum primeiro:

struct Invoice {
total: u32,
}
fn print_invoice(inv: &Invoice) {
println!("Total da fatura: R$ {}", inv.total);
}
fn main() {
print_invoice(&Invoice { total: 120 });
}

Saída:

Total da fatura: R$ 120
▶ Experimente você mesmo

Correção 2: Acrescente a linha use que o rustc sugere

Seção intitulada “Correção 2: Acrescente a linha use que o rustc sugere”

Escolha esta quando a ajuda disser consider importing this struct (ou enum, ou type alias). Tipos da biblioteca padrão que ficam fora do prelude, como HashMap, ParseIntError ou Ordering, precisam de uma linha use. Aqui uma função retorna um erro de conversão:

error[E0425]: cannot find type `ParseIntError` in this scope
--> src/main.rs:1:40
|
1 | fn parse_age(text: &str) -> Result<u8, ParseIntError> {
| ^^^^^^^^^^^^^ not found in this scope
|
help: consider importing this struct
|
1 + use std::num::ParseIntError;
|

O rótulo diz “não encontrado neste escopo”, e a ajuda mostra a linha use que falta.

Copie a linha sugerida para o começo do arquivo:

use std::num::ParseIntError;
fn parse_age(text: &str) -> Result<u8, ParseIntError> {
text.trim().parse()
}
fn main() {
println!("{:?}", parse_age(" 42 "));
println!("{:?}", parse_age("quarenta").is_err());
}

Saída:

Ok(42)
true
▶ Experimente você mesmo

Se você escreveu HashMap::new() (um caminho com ::) em vez de um tipo numa assinatura, o erro é o E0433, e a mesma linha use resolve. Se o rustc sugerir vários imports, leia todos antes de escolher; são tipos diferentes que têm o mesmo nome.

Correção 3: Declare o parâmetro de tipo genérico

Seção intitulada “Correção 3: Declare o parâmetro de tipo genérico”

Escolha esta quando a ajuda disser you might be missing a type parameter. Em Rust, T não é uma palavra especial. É um nome que você inventa, e você precisa anunciá-lo entre sinais de menor e maior depois do nome da função. Sem <T>, o Rust procura um tipo real chamado T:

error[E0425]: cannot find type `T` in this scope
--> src/main.rs:1:21
|
1 | fn largest(items: &[T]) -> &T {
| ^ not found in this scope
|
help: you might be missing a type parameter
|
1 | fn largest<T>(items: &[T]) -> &T {
| +++

Você recebe o mesmo erro uma vez para cada lugar onde T aparece. Acrescente <T>, junto com qualquer trait de que a função precise. Para comparar itens com >, T precisa implementar PartialOrd:

fn largest<T: PartialOrd>(items: &[T]) -> &T {
let mut best = &items[0];
for item in items {
if item > best {
best = item;
}
}
best
}
fn main() {
println!("{}", largest(&[34, 50, 25, 100, 65]));
println!("{}", largest(&['y', 'm', 'a', 'q']));
}

Saída:

100
y
▶ Experimente você mesmo

O mesmo vale para structs: struct Wrapper { items: Vec<Item> } falha, a não ser que você escreva struct Wrapper<Item> ou defina um tipo Item de verdade. Se deixar o : PartialOrd de fora, você recebe o E0369 no >. Veja Genéricos.

Escolha esta quando o tipo é seu, mas fica em outro módulo. Uma surpresa comum: um módulo dentro do seu arquivo também não enxerga os tipos do começo do arquivo. Cada módulo tem o seu próprio escopo:

error[E0425]: cannot find type `Order` in this scope
--> src/main.rs:7:26
|
7 | pub fn print(order: &Order) -> String {
| ^^^^^ not found in this scope
|
help: consider importing this struct
|
7 + use crate::Order;
|

O 7 + quer dizer “acrescente esta linha dentro do módulo, na linha 7”. crate::Order é o caminho a partir da raiz do seu crate; super::Order (“a partir do módulo pai”) também funciona:

struct Order {
id: u32,
total: u32,
}
mod receipts {
use crate::Order;
pub fn print(order: &Order) -> String {
format!("Pedido #{}: R$ {}", order.id, order.total)
}
}
fn main() {
let order = Order { id: 7, total: 42 };
println!("{}", receipts::print(&order));
}

Saída:

Pedido #7: R$ 42
▶ Experimente você mesmo

A outra direção funciona do mesmo jeito: um tipo definido em mod shop precisa de pub struct Product e de use crate::shop::Product; (ou do caminho completo shop::Product) para que o main possa usá-lo. Você vai encontrar isso mais em mod tests, onde use super::*; no começo importa tudo do módulo pai.

Um tipo de um arquivo que você não declarou. fn save(user: models::User) com um arquivo src/models.rs, mas sem a linha mod models;, não dá E0412 nem E0425, e sim o E0433: cannot find module or crate `models` in this scope (não foi encontrado o módulo ou crate models neste escopo). Correção: acrescente mod models; no começo do main.rs e deixe a struct pub.

Self fora de um impl. fn new_counter() -> Self fora de qualquer bloco tem o seu próprio código, o E0411: cannot find type `Self` in this scope, com o rótulo `Self` is only available in impls, traits, and type definitions (Self só existe em impls, traits e definições de tipo). Correção: leve a função para dentro de impl Counter { ... }, ou escreva Counter em vez de Self.

Um trait em vez de um tipo. impl Display for Point sem importar Display dá o E0405, cannot find trait `Display` in this scope (não foi encontrado o trait Display), com help: consider importing this trait e use std::fmt::Display;. Mesma ideia, mesma correção: acrescente a linha use. Veja Traits.

  • E0425: não foi encontrado o valor, a função e, desde o Rust 1.93, também o tipo. É o código que você vai ver de fato hoje.
  • E0433: não foi encontrada a primeira parte de um caminho como HashMap::new() ou models::User.
  • E0432: unresolved import, quando a própria linha use aponta para o nada.
  • E0603: o tipo foi encontrado, mas não é pub.
  • E0405 (trait não encontrado) e E0411 (Self fora de um impl): os primos próximos mostrados acima.
  • Todos os erros do compilador: a lista completa de páginas de erro.

Teste o que aprendeu

1. Você seguiu um tutorial que mostra error[E0412]: cannot find type, mas o seu compilador mostra error[E0425]: cannot find type. Por quê?

2. fn first(items: &[T]) -> &T dá cannot find type T. Como corrigir?

3. Uma função dentro de mod billing usa Order, uma struct definida no começo do main.rs. Qual linha, dentro do módulo, resolve?

Pontuação: 0 / 3