Rust 错误 E0433:failed to resolve, use of undeclared type(使用了未声明的类型)
E0433 的意思是:你写了 HashMap::new() 或 rand::rng() 这样的路径,而 Rust 不知道它的第一部分是什么。几乎总是缺了一行:一个 use、Cargo.toml 里的一个依赖,或者一个 mod 声明。好消息是,rustc 通常会把那一行原样打印出来,让你直接复制。本页属于 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; |下面这段程序会产生这个错误:
fn main() { let mut stock = HashMap::new(); stock.insert("apples", 12); println!("{:?}", stock.get("apples"));}旧版本的 Rust 会把同一个错误打印成 “failed to resolve: use of undeclared type HashMap”。根据缺的是什么,标注也可能写成 use of unresolved module or unlinked crate(缺的是 crate 或模块),而不是 use of undeclared type。这些都是 E0433,修复方法也一样。
这个错误是什么意思
Section titled “这个错误是什么意思”^^^^^^^ 指向 HashMap,也就是 :: 前面的部分。要调用 HashMap::new(),Rust 得先找到一个叫 HashMap 的东西。它查看了第 2 行能看到的所有东西,没找到这个名字,所以连 new 都没法开始找。
help: 这一行才是重点。rustc 搜索了标准库,在 std::collections 里找到一个叫 HashMap 的结构体,并给出能让它可见的那行 use。1 + 的意思是“把这一行加为第 1 行”。
这就像你问图书管理员要“那本书的第 3 章”,却不说是哪本书。管理员知道很多书都有第 3 章,但得先知道书名。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”每个 Rust 文件里自动可见的名字只有一小部分,这叫作 prelude(预导入):Vec、String、Option、Some、None、Result、Ok、Err、Box 和几个 trait。其他所有东西,包括 HashMap、HashSet、fs 和 Ordering,都得用 use 引入,或者写出完整路径。
这样 prelude 能保持精简,也能避免名字冲突。比如标准库里就有两个不同的 Ordering 类型,你自己的代码里也可能有 Duration 或 Result。Rust 不会去猜你指的是哪一个。你在文件顶部说一次,每个读代码的人都能看出每个名字来自哪里。
crate 和模块也一样:crate 只有列在 Cargo.toml 里之后,你的代码才能用它;模块只有写了 mod 行之后才存在。见 模块 和 Cargo 与 crate。
修复 1:加上 rustc 建议的 use 行
Section titled “修复 1:加上 rustc 建议的 use 行”如果 help: 写的是 consider importing(考虑导入),就选这个办法。这是到目前为止最常见的修复。把建议的那一行复制到文件顶部:
use std::collections::HashMap;
fn main() { let mut stock = HashMap::new(); stock.insert("apples", 12); println!("{:?}", stock.get("apples"));}输出:
Some(12)另一个选择是在调用的地方写完整路径:std::collections::HashMap::new()。这样也行,但每次用都得重复写,所以通常还是加一行 use。关于这个类型的更多内容,见 HashMap。
如果 rustc 给出了好几个导入(consider importing one of these,考虑导入其中之一),先看清楚再选。它们是名字相同的不同类型,只有一个是你想要的。
修复 2:改正类型名,或者声明这个类型
Section titled “修复 2:改正类型名,或者声明这个类型”如果这个名字是你自己的类型,就选这个办法。如果完全没有 help:,说明这个类型还不存在;如果是拼写错误,rustc 会指出相似的名字:
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(); | +那一行下面的 + 标出了漏掉的字母。改正拼写:
struct Inventory { items: Vec<String>,}
impl Inventory { fn new() -> Self { Inventory { items: Vec::new() } }}
fn main() { let stock = Inventory::new(); println!("{} 件物品", stock.items.len());}输出:
0 件物品如果 Order::new() 报 E0433 却没有任何建议,说明你还没写 struct Order(或者它在一个你还没用 mod 声明的文件里)。还要检查大小写:inventory::new() 和 Inventory::new() 是两个不同的名字。
修复 3:写上类型所在的模块
Section titled “修复 3:写上类型所在的模块”如果类型或枚举定义在某个模块里,而你在模块外面使用它,就选这个办法。这里枚举在 mod traffic 里,main 却直接写了 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; |导入这个枚举(或者写成 traffic::Light::Green)。注意,你导入的是枚举,之后每个变体仍然要写成 Light::Green:
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:?}:能走吗?{}", can_go(&now));}输出:
Green:能走吗?true变体路径正好有两部分:Enum::Variant。如果多写了一部分,比如 Light::Red::Green,就会得到 E0433,信息是 cannot find module `Red` in `Light` ,标注是 `Red` is a variant, not a module(Red 是变体,不是模块)。见 枚举。
修复 4:添加 crate,或者声明模块
Section titled “修复 4:添加 crate,或者声明模块”如果标注写的是 use of unresolved module or unlinked crate,就选这个办法。路径的第一部分是一个 Rust 不认识的 crate 或模块:
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`如果是 crates.io 上的 crate,就在项目文件夹里运行 cargo add rand。如果是 fs 这样的标准库模块,rustc 会建议加上 use std::fs;。如果是你自己的文件,比如 src/inventory.rs,help 会说 to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module(要使用源文件 src/inventory.rs,请在这个文件里用 mod inventory 声明模块):
src/├── main.rs inventory::count_items() ← 顶部需要 `mod inventory;`└── inventory.rs pub fn count_items() -> u32 { 42 }下面是放在一个文件里的同一个程序,模块直接写在文件里,这样就能在 Playground 上运行:
mod inventory { pub fn count_items() -> u32 { 42 }}
fn main() { println!("库存数量:{}", inventory::count_items());}输出:
库存数量:42如果用单独的文件,唯一的变化就是把 mod inventory { ... } 改成 mod inventory;,再把里面的内容移到 src/inventory.rs。
那 extern crate 呢?
Section titled “那 extern crate 呢?”你可能会在老代码里看到 extern crate rand;。从 2018 edition 开始就不需要它了:crate 一旦写进 Cargo.toml,就能直接使用。加上 extern crate 并不能修复 E0433。没有依赖的话,它只会把错误换成 E0463,也就是 can't find crate for rand(找不到 rand 这个 crate)。真正的修复是 cargo add。
用 cmp 比较。 带 Ordering::Less 分支的 match a.cmp(&b) 会报 E0433,rustc 会建议两个导入:use std::cmp::Ordering; 和 use std::sync::atomic::Ordering;。你要的是 std::cmp::Ordering,atomic 那个是给线程用的。见 match。
mod tests 块里的测试。 测试模块是一个子模块,不导入就看不到你的类型。在 mod tests 里写 Inventory::new() 会报 E0433,并附带 help: consider importing this struct 和 use crate::Inventory;。修复:在测试模块顶部加上 use super::*;。见 测试。
从文档或博客里粘贴的代码。 示例代码经常省略 use 行。fs::read_to_string(...) 会报 cannot find module or crate `fs` in this scope,help 是 use std::fs;。修复:加上 rustc 给出的导入,或者到这个项的文档页面上查它的路径。
- E0432:同一类问题出现在
use行上,即unresolved import(无法解析的导入)。 - E0425:找不到某个值或函数(不涉及
::),比如拼错的变量名。当前的 rustc 也会对类型位置上缺失的类型报 E0425,比如let m: HashMap<&str, u32>;旧版本把它叫作 E0412。同样一行use就能修复。 - E0599:类型找到了,但
::后面的方法或变体不存在,比如Light::Blue。 - E0463:
can't find crate(找不到 crate),没有添加依赖却写了extern crate时会报这个错。 - 所有编译错误:全部错误页面的列表。
小测验
1. 为什么 Vec::new() 不用导入就能用,HashSet::new() 却报 E0433?
2. 对于你的 match a.cmp(&b),rustc 同时建议了 use std::cmp::Ordering; 和 use std::sync::atomic::Ordering;。选哪个?
3. rand::rng() 报 E0433,标注是 “use of unresolved module or unlinked crate”。怎么修复?
得分: 0 / 3
- E0433 — Rust error codes index(英文):官方说明,涵盖未声明的类型和未链接的 crate 两种情况。
- 使用
use关键字将路径引入作用域 —《Rust 程序设计语言》:use怎么用,以及为什么导入HashMap这类类型是很正常的事。 - 引用模块树中项的路径 —《Rust 程序设计语言》:完整路径、
crate::和super::。 std::prelude— 标准库文档(英文):不用use就可见的名字的完整列表。- Path and module changes in Rust 2018 — Edition Guide(英文):为什么不再需要
extern crate。