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.
A mensagem de erro
Seção intitulada “A mensagem de erro”É 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 here2 | 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 here2 | 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 que significa
Seção intitulada “O que significa”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
Tsem 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.
Por que o Rust faz isso
Seção intitulada “Por que o Rust faz isso”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.
Como corrigir
Seção intitulada “Como corrigir”Correção 1: Corrija a grafia, ou defina o tipo
Seção intitulada “Correção 1: Corrija a grafia, ou defina o tipo”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$ 120Correçã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)trueSe 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:
100yO 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.
Correção 4: Importe um tipo de outro módulo
Seção intitulada “Correção 4: Importe um tipo de outro módulo”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$ 42A 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.
Onde você costuma ver esse erro
Seção intitulada “Onde você costuma ver esse erro”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.
Erros relacionados
Seção intitulada “Erros relacionados”- 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()oumodels::User. - E0432: unresolved import, quando a própria linha
useaponta para o nada. - E0603: o tipo foi encontrado, mas não é
pub. - E0405 (trait não encontrado) e E0411 (
Selffora 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
Seção intitulada “Teste o que aprendeu”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
Para saber mais
Seção intitulada “Para saber mais”- E0412 — Rust error codes index (em inglês): a página oficial, com o aviso de que este código não é mais emitido, e os exemplos clássicos.
- E0425 — Rust error codes index (em inglês): o código que o compilador de hoje usa para este erro.
- Generic Data Types — The Rust Book (em inglês): como declarar
<T>, com a mesma funçãolargestda Correção 3. - Bringing Paths into Scope with the
useKeyword — The Rust Book (em inglês):use,crate::esuper::para tipos de outros módulos. std::prelude— documentação da biblioteca padrão (em inglês): a lista de nomes que você pode usar sem importar.