Rust 错误 E0432:unresolved import(无法解析的导入)
E0432 的意思是:你的某一行 use 指向了 Rust 找不到的东西。可能是 crate 还没写进 Cargo.toml,可能是路径里有个小拼写错误,也可能是文件明明存在,Rust 却不知道它是一个模块。看起来有点吓人,但几乎总是改一行就好,而且编译器通常会告诉你是哪一行。本页属于 Rust 编译错误详解 系列。
error[E0432]: unresolved import `rand` --> src/main.rs:1:5 |1 | use rand::random_range; | ^^^^ 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`下面这段程序会产生这个错误。它放在一个用 cargo new 新建的项目里,[dependencies] 下面什么都没有:
use rand::random_range;
fn main() { let roll = random_range(1..=6); println!("You rolled {roll}");}^^^^ 下面的文字会随原因变化。下面每一种都是 E0432,各自对应后面不同的修复方法:
| 标注上写的是 | 通常哪里出了问题 | 修复 |
|---|---|---|
use of unresolved module or unlinked crate |
Cargo.toml 里没有这个 crate,或者文件没有对应的 mod 行 |
修复 1 或修复 3 |
could not find `collection` in `std` |
路径中间有拼写错误 | 修复 2 |
no `Hashmap` in `collections` |
最后一个名字拼错了(或大小写不对) | 修复 2 |
could not find `inventory` in the crate root |
用 crate:: 路径指向了一个没有声明的模块 |
修复 3 |
no external crate |
路径的起点选错了模块 | 修复 4 |
这个错误是什么意思
Section titled “这个错误是什么意思”use 行是一个快捷方式。use rand::random_range; 的意思是:“从现在起,random_range 指的就是 rand::random_range 那个东西。”在建立这个快捷方式之前,Rust 得沿着路径一段一段地走:先找到 rand,再在它里面找 random_range。
^^^^ 标出的是第一个失败的那一段。这里是 rand,也就是最前面那一段,所以 Rust 根本还没去找 random_range。help: 那一行猜测了原因:rand 是 crates.io 上的一个 crate,而这个项目还没有添加它。
这就像你告诉出租车司机去“春田镇海港街 12 号”,可镇名写错了,司机连从哪条街找起都不知道。
Rust 为什么要这样做
Section titled “Rust 为什么要这样做”Rust 在编译时就解析每一条路径,而不是等到程序运行时。它不会“以防万一”提前加载任何东西。你的代码只能看到三类东西:Cargo.toml 里列出的 crate(再加上 std)、你用 mod 声明的模块,以及它们里面的项。如果某一行 use 提到的东西不在这个范围内,Rust 会立刻停下来,而不是去猜。
这其实是好事。在 Python 或 JavaScript 里,拼错的导入往往要等到那一行真正运行时才会失败,说不定是在生产环境里。在 Rust 里,它连编译都过不了。这也意味着,你从没添加过的 crate 永远不可能偷偷混进你的程序。
从 2018 edition 开始,use 路径从下面几个地方之一开始:某个 crate 的名字(std、rand)、crate(你自己 crate 的根)、self(当前模块)、super(父模块),或者当前模块里声明的某个模块。模块 一课会详细讲这些,Cargo 与 crate 则讲解依赖。
修复 1:用 cargo add 添加 crate
Section titled “修复 1:用 cargo add 添加 crate”如果路径的第一段是 crates.io 上的 crate,比如 rand、serde 或 regex,并且 help: 那一行提到了 cargo add,就选这个办法。这是最常见的原因,从博客文章里复制代码时尤其如此。在包含 Cargo.toml 的文件夹里运行:
cargo add randCargo 会找到最新版本,并帮你在 Cargo.toml 里加上一行:
[dependencies]rand = "0.10.3"现在同样的代码就能编译了。这个版本打印的是一个检查结果,而不是点数本身,所以每次输出都一样:
use rand::random_range;
fn main() { let roll = random_range(1..=6); println!("点数在 1 到 6 之间:{}", (1..=6).contains(&roll));}输出:
点数在 1 到 6 之间:true这里有两个地方容易踩坑。第一,名字里带短横线的 crate,在代码里要写成下划线:你运行的是 cargo add tracing-subscriber,写的却是 use tracing_subscriber::...。第二,即使这个 crate 是你工作空间的依赖,它仍然必须列在使用它的那个包的 Cargo.toml 里。
修复 2:改正路径的拼写
Section titled “修复 2:改正路径的拼写”如果标注写的是 could not find `X` in `Y` 或 no `X` in `Y`,就选这个办法。路径中间或末尾的某个名字拼错了。一个经典的例子:
error[E0432]: unresolved import `std::collection` --> src/main.rs:1:10 |1 | use std::collection::HashMap; | ^^^^^^^^^^ could not find `collection` in `std`这个模块叫 collections,末尾有个 s。名字还区分大小写:use std::collections::Hashmap; 会报 no `Hashmap` in `collections`,rustc 还会加上 help: a similar name exists in the module(模块里有一个相似的名字),并给出正确的拼写。改好的导入:
use std::collections::HashMap;
fn main() { let mut stock: HashMap<&str, u32> = HashMap::new(); stock.insert("apples", 12); println!("{:?}", stock.get("apples"));}输出:
Some(12)如果不确定准确的路径,就去 标准库文档(英文)里搜一下。每个项的页面顶部都写着它的完整路径。关于这个类型的更多内容,见 HashMap。
修复 3:用 mod 声明模块
Section titled “修复 3:用 mod 声明模块”如果你新建了一个文件,比如 src/inventory.rs,而 use inventory::... 找不到它,就选这个办法。在 Rust 里,文件在被父文件声明之前不算模块。你的项目是这样的:
src/├── main.rs use inventory::count_items; ← 没有 `mod inventory;`└── inventory.rs pub fn count_items() -> u32 { 42 }rustc 会明确告诉你缺了什么:
error[E0432]: unresolved import `inventory` --> src/main.rs:1:5 |1 | use inventory::count_items; | ^^^^^^^^^ use of unresolved module or unlinked crate `inventory` |help: to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module |1 + mod inventory; |在 src/main.rs 的顶部加上 mod inventory;(如果这个模块属于你的库,就加在 src/lib.rs 里)。改写成 use crate::inventory::count_items; 没有用,它会报 could not find `inventory` in the crate root,因为模块仍然没有声明。
Playground 里所有代码都在一个文件中,所以这里用 mod inventory { ... } 把模块直接写在文件里。它和单独的文件效果完全一样:
mod inventory { pub fn count_items() -> u32 { 42 }}
use inventory::count_items;
fn main() { println!("库存数量:{}", count_items());}输出:
库存数量:42每个模块只在它的父模块里声明一次。其他文件再通过 use crate::inventory::... 访问它。不要在每个用到它的文件里都加 mod inventory;。
修复 4:让路径从正确的地方开始
Section titled “修复 4:让路径从正确的地方开始”如果导入写在某个模块里,而要用的项在你自己 crate 的另一个模块里,就选这个办法。这里 receipt 在 shop 里面,想用 shop::store_name:
mod shop { pub fn store_name() -> &'static str { "Ferris Fruits" }
pub mod receipt { use store_name; // ❌ looks in the wrong place
pub fn header() -> String { format!("== {} ==", store_name()) } }}error[E0432]: unresolved import `store_name` --> src/main.rs:7:13 |7 | use store_name; // ❌ looks in the wrong place | ^^^^^^^^^^ no external crate `store_name`(注释保留英文,因为它出现在错误信息里,意思是“找错了地方”。)
use 路径开头的一个单独名字,意思是“一个 crate,或者就在当前模块里声明的东西”。store_name 两者都不是,所以 Rust 去找了一个叫这个名字的 crate。你得告诉它从哪里开始找:
| 前缀 | 起点 | 示例 |
|---|---|---|
crate:: |
你的 crate 的根(main.rs 或 lib.rs) |
use crate::shop::prices::price_of; |
super:: |
父模块 | use super::store_name; |
self:: |
当前模块 | use self::lines::line; |
三种写法放在一个程序里:
mod shop { pub fn store_name() -> &'static str { "Ferris Fruits" }
pub mod prices { pub fn price_of(item: &str) -> u32 { if item == "apple" { 3 } else { 5 } } }
pub mod receipt { use super::store_name; // 父模块:shop use crate::shop::prices::price_of; // 从 crate 根开始 use self::layout::line; // 当前模块的子模块
mod layout { pub fn line(item: &str, price: u32) -> String { format!("{item}: {price}") } }
pub fn print(item: &str) { println!("== {} ==", store_name()); println!("{}", line(item, price_of(item))); } }}
fn main() { shop::receipt::print("apple");}输出:
== Ferris Fruits ==apple: 3这里写 use layout::line; 也行,因为 layout 就声明在当前模块里;self:: 只是把这一点写明白。拿不准的时候,用 crate:: 加完整路径,在 crate 里任何地方都管用,rustc 也经常这样建议:先是 help: a similar path exists(存在一个相似的路径),后面跟着 crate:: 版本。
为旧版 crate 写的代码。 很多教程用的是 rand 0.8。换成 rand 0.10 就会得到:
error[E0432]: unresolved import `rand::thread_rng` --> src/main.rs:1:5 |1 | use rand::thread_rng; | ^^^^^^^^^^^^^^^^ no `thread_rng` in the root修复:在 docs.rs 上查看你 Cargo.toml 里那个版本的 crate 文档。这里的新名字是 rand::rng()。见 随机数。
同时有 main.rs 和 lib.rs 的包。 它们是两个独立的 crate。在 main.rs 里,crate:: 指的是这个二进制 crate,所以即使 lib.rs 里有 pub mod inventory;,use crate::inventory::count_items; 也会报 could not find `inventory` in the crate root。修复:用包名,use shop_app::inventory::count_items;(短横线要换成下划线)。
项存在,但是私有的。 这是另一个错误 E0603,不是 E0432:
error[E0603]: function `count_items` is private --> src/main.rs:7:16 |7 | use inventory::count_items; | ^^^^^^^^^^^ private function修复:在 fn 前面加上 pub(路径上经过的每个 mod 前面也要加,因为私有模块会报 module `prices` is private)。见 模块。
- E0433:代码里的某条路径(比如
HashMap::new()或rand::rng())无法解析。原因相同,只是不在use行上。 - E0425:找不到某个值或函数,常常加上同样的
use行就能解决。 - E0603:导入找到了,但它是私有的。加上
pub。 - E0463:
can't find crate(找不到 crate),crate 不在Cargo.toml里时写extern crate rand;就会报这个错。 - 所有编译错误:全部错误页面的列表。
小测验
1. 你把 use serde::Serialize; 复制进一个新项目,得到 E0432,说 crate serde 无法解析或没有链接。怎么修复?
2. 你新建了 src/billing.rs,但 main.rs 里的 use billing::total; 报错了。缺了什么?
3. 在 mod shop { mod receipt { ... } } 里,receipt 怎样导入直接定义在 shop 里的函数?
得分: 0 / 3
- E0432 — Rust error codes index(英文):官方说明,包括 Rust 2018 中路径的变化。
- 使用
use关键字将路径引入作用域 —《Rust 程序设计语言》:use怎么用,包括外部包和嵌套路径。 - 引用模块树中项的路径 —《Rust 程序设计语言》:以
crate::开头的绝对路径、相对路径,以及super。 - 将模块拆分成多个文件 —《Rust 程序设计语言》:模块放在单独文件里时,
mod该写在哪里。 cargo add— The Cargo Book(英文):添加依赖的所有选项,包括 feature。