Pular para o conteúdo

Erro E0433 do Rust: failed to resolve, use of undeclared type

O E0433 quer dizer que você escreveu um caminho como HashMap::new() ou rand::rng(), e o Rust não sabe o que é a primeira parte dele. Quase sempre falta uma linha: um use, uma dependência no Cargo.toml ou uma declaração mod. A boa notícia é que o rustc normalmente mostra exatamente essa linha para você copiar. Para os outros erros desta série, veja Erros do compilador Rust.

error[E0433]: cannot find type `HashMap` in this scope
--> src/main.rs:2:21
|
2 | let mut stock = HashMap::new();
| ^^^^^^^ use of undeclared type `HashMap`
|
help: consider importing this struct
|
1 + use std::collections::HashMap;
|

Em português: “não foi possível encontrar o tipo HashMap neste escopo” e “uso de um tipo não declarado”. O compilador sugere importar a struct com use std::collections::HashMap;.

Este é o programa que gera o erro:

fn main() {
let mut stock = HashMap::new();
stock.insert("apples", 12);
println!("{:?}", stock.get("apples"));
}

Versões mais antigas do Rust mostram o mesmo erro como “failed to resolve: use of undeclared type HashMap” (falha ao resolver: uso de um tipo não declarado). Dependendo do que está faltando, o rótulo também pode dizer use of unresolved module or unlinked crate (uso de um módulo não resolvido ou de um crate não vinculado, para um crate ou módulo) em vez de use of undeclared type. Todos esses são E0433, e a correção é a mesma.

O ^^^^^^^ aponta para HashMap, a parte antes do ::. Para chamar HashMap::new(), o Rust primeiro precisa encontrar algo chamado HashMap. Ele olhou tudo o que está visível na linha 2 e não achou nada com esse nome, então nem consegue começar a procurar o new.

A linha help: é a parte importante. O rustc vasculhou a biblioteca padrão, achou uma struct chamada HashMap em std::collections e mostra a linha use que a tornaria visível. O 1 + quer dizer “acrescente isto como linha 1”.

É como pedir a uma bibliotecária “o capítulo 3 daquele livro” sem dizer qual livro. Ela sabe que existe um capítulo 3 em vários livros, mas precisa primeiro do título.

Só um conjunto pequeno de nomes fica visível automaticamente em todo arquivo Rust. Ele se chama prelude: Vec, String, Option, Some, None, Result, Ok, Err, Box e alguns traits. Todo o resto, incluindo HashMap, HashSet, fs e Ordering, precisa ser trazido com use ou escrito com o caminho completo.

Isso mantém o prelude pequeno e evita conflitos de nomes. A biblioteca padrão tem dois tipos Ordering diferentes, por exemplo, e o seu próprio código pode ter um Duration ou um Result também. O Rust não vai adivinhar qual você quis dizer. Você diz uma vez, no topo do arquivo, e qualquer pessoa lendo vê de onde vem cada nome.

O mesmo vale para crates e módulos: um crate só existe para o seu código depois de estar listado no Cargo.toml, e um módulo só depois de uma linha mod. Veja Módulos e Cargo e crates.

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 o help: disser consider importing (considere importar). É de longe a correção mais comum. Copie a linha sugerida para o topo do arquivo:

use std::collections::HashMap;
fn main() {
let mut stock = HashMap::new();
stock.insert("apples", 12);
println!("{:?}", stock.get("apples"));
}

Saída:

Some(12)
▶ Experimente você mesmo

A outra opção é escrever o caminho completo na chamada, std::collections::HashMap::new(). Isso também funciona, mas você teria que repeti-lo em todo lugar, então a linha use é a escolha normal. Mais sobre esse tipo em HashMaps.

Se o rustc oferecer vários imports (consider importing one of these, considere importar um destes), leia todos antes de escolher. São tipos diferentes que têm o mesmo nome, e só um deles é o que você quis dizer.

Correção 2: Corrija o nome do tipo ou declare o tipo

Seção intitulada “Correção 2: Corrija o nome do tipo ou declare o tipo”

Escolha esta quando o nome é de um tipo seu. Se não houver nenhum help:, o tipo ainda não existe; se houver um erro de digitação, o rustc aponta o nome parecido:

error[E0433]: cannot find type `Invetory` in this scope
--> src/main.rs:12:17
|
12 | let stock = Invetory::new();
| ^^^^^^^^ use of undeclared type `Invetory`
|
help: a struct with a similar name exists
|
12 | let stock = Inventory::new();
| +

O help diz que existe uma struct com nome parecido. O + embaixo da linha mostra a letra que faltou. Corrija a grafia:

struct Inventory {
items: Vec<String>,
}
impl Inventory {
fn new() -> Self {
Inventory { items: Vec::new() }
}
}
fn main() {
let stock = Inventory::new();
println!("{} itens", stock.items.len());
}

Saída:

0 itens
▶ Experimente você mesmo

Se Order::new() der E0433 sem nenhuma sugestão, você ainda não escreveu struct Order (ou ela está num arquivo que você não declarou com mod). Confira também as maiúsculas: inventory::new() e Inventory::new() são nomes diferentes.

Escolha esta quando o tipo ou enum está definido dentro de um módulo e você o usa de fora. Aqui o enum está em mod traffic, mas main escreve Light::Green:

error[E0433]: cannot find type `Light` in this scope
--> src/main.rs:11:15
|
11 | let now = Light::Green;
| ^^^^^ use of undeclared type `Light`
|
help: consider importing this enum
|
1 + use crate::traffic::Light;
|

O compilador não encontra o tipo Light e sugere importar o enum. Importe o enum (ou escreva traffic::Light::Green). Repare que você importa o enum e, mesmo assim, continua escrevendo Light::Green para cada variante:

mod traffic {
#[derive(Debug)]
pub enum Light {
Red,
Yellow,
Green,
}
}
use crate::traffic::Light;
fn can_go(light: &Light) -> bool {
match light {
Light::Green => true,
Light::Yellow | Light::Red => false,
}
}
fn main() {
let now = Light::Green;
println!("{now:?}: pode seguir = {}", can_go(&now));
}

Saída:

Green: pode seguir = true
▶ Experimente você mesmo

O caminho de uma variante tem exatamente duas partes: Enum::Variant. Se você escrever uma parte a mais, como Light::Red::Green, recebe o E0433 com cannot find module `Red` in `Light` e o rótulo `Red` is a variant, not a module (Red é uma variante, não um módulo). Veja Enums.

Correção 4: Adicione o crate ou declare o módulo

Seção intitulada “Correção 4: Adicione o crate ou declare o módulo”

Escolha esta quando o rótulo disser use of unresolved module or unlinked crate. A primeira parte do caminho é um crate ou um módulo que o Rust não conhece:

error[E0433]: cannot find module or crate `rand` in this scope
--> src/main.rs:4:19
|
4 | let mut rng = rand::rng();
| ^^^^ use of unresolved module or unlinked crate `rand`
|
= help: if you wanted to use a crate named `rand`, use `cargo add rand` to add it to your `Cargo.toml`

O help sugere usar cargo add rand para colocar o crate no Cargo.toml. Para um crate do crates.io, é isso mesmo: rode esse comando na pasta do projeto. Para um módulo da biblioteca padrão como fs, o rustc sugere use std::fs;. E para um arquivo seu, digamos src/inventory.rs, o help diz to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module (para usar o arquivo, declare o módulo com mod inventory neste arquivo):

src/
├── main.rs inventory::count_items() ← precisa de `mod inventory;` no topo
└── inventory.rs pub fn count_items() -> u32 { 42 }

Aqui está o mesmo programa num arquivo só, com o módulo escrito direto no código para rodar no Playground:

mod inventory {
pub fn count_items() -> u32 {
42
}
}
fn main() {
println!("Itens em estoque: {}", inventory::count_items());
}

Saída:

Itens em estoque: 42
▶ Experimente você mesmo

Com um arquivo separado, a única mudança é que mod inventory { ... } vira mod inventory; e o corpo vai para src/inventory.rs.

Você pode ver extern crate rand; em código antigo. Desde a edição 2018 ele não é necessário: quando o crate está no Cargo.toml, você pode usá-lo direto. Acrescentar extern crate não resolve o E0433. Sem a dependência, ele só troca o erro pelo E0463, can't find crate for rand (crate não encontrado). A correção de verdade é o cargo add.

Comparar com cmp. match a.cmp(&b) com braços Ordering::Less dá E0433, e o rustc sugere dois imports: use std::cmp::Ordering; e use std::sync::atomic::Ordering;. Você quer o std::cmp::Ordering; o atômico é para threads. Veja Match.

Testes num bloco mod tests. Um módulo de testes é um módulo filho, então ele não enxerga os seus tipos sem importá-los. Inventory::new() dentro de mod tests dá E0433 com help: consider importing this struct e use crate::Inventory;. Correção: coloque use super::*; no topo do módulo de testes. Veja Testes.

Código colado da documentação ou de posts de blog. Os exemplos muitas vezes pulam as linhas use. fs::read_to_string(...) falha com cannot find module or crate `fs` in this scope e o help use std::fs;. Correção: acrescente o import que o rustc mostra ou procure o caminho do item na página de documentação dele.

  • E0432: o mesmo tipo de problema numa linha use, unresolved import (import não resolvido).
  • E0425: não foi possível encontrar um valor ou uma função (sem :: no meio), como uma variável com erro de digitação. O rustc atual também usa o E0425 para um tipo que falta numa posição de tipo, como let m: HashMap<&str, u32>; versões mais antigas chamam isso de E0412. A mesma linha use resolve.
  • E0599: o tipo foi encontrado, mas o método ou a variante depois do :: não existe, como Light::Blue.
  • E0463: can't find crate, por causa de um extern crate sem a dependência.
  • Todos os erros do compilador: a lista completa de páginas de erro.

Teste o que aprendeu

1. Por que HashSet::new() dá E0433 quando Vec::new() funciona sem nenhum import?

2. O rustc sugere use std::cmp::Ordering; e também use std::sync::atomic::Ordering; para o seu match a.cmp(&b). Qual você escolhe?

3. rand::rng() dá E0433 com o rótulo 'use of unresolved module or unlinked crate'. O que resolve?

Pontuação: 0 / 3