Bỏ qua để đến nội dung

Lỗi Rust E0432: unresolved import (không tìm thấy thứ cần import)

E0432 nghĩa là một dòng use của bạn trỏ tới thứ mà Rust không tìm thấy. Có thể crate chưa có trong Cargo.toml, có thể đường dẫn bị gõ nhầm một chút, hoặc có thể một file có tồn tại nhưng Rust không biết đó là một module. Trông thì đáng sợ, nhưng gần như lúc nào cũng chỉ cần sửa một dòng, và trình biên dịch thường cho bạn biết là dòng nào. Trang này thuộc hướng dẫn về lỗi trình biên dịch.

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`

Trình biên dịch báo rằng nó không tìm thấy rand: đó không phải module đã khai báo, cũng không phải crate đã được liên kết, và gợi ý chạy cargo add rand để thêm vào Cargo.toml.

Đây là chương trình gây ra lỗi, trong một project vừa tạo bằng cargo new và chưa có gì dưới [dependencies]:

use rand::random_range;
fn main() {
let roll = random_range(1..=6);
println!("You rolled {roll}");
}

Dòng chữ dưới ^^^^ thay đổi tùy nguyên nhân. Mỗi dòng sau đều là E0432, và mỗi dòng dẫn tới một cách sửa khác nhau bên dưới:

Nhãn ghi gì Thường sai ở đâu Cách sửa
use of unresolved module or unlinked crate crate chưa có trong Cargo.toml, hoặc một file chưa có dòng mod Cách sửa 1 hoặc Cách sửa 3
could not find `collection` in `std` gõ nhầm ở giữa đường dẫn Cách sửa 2
no `Hashmap` in `collections` gõ nhầm (hoặc sai chữ hoa/thường) ở tên cuối Cách sửa 2
could not find `inventory` in the crate root đường dẫn crate:: tới một module chưa được khai báo Cách sửa 3
no external crate đường dẫn bắt đầu ở sai module Cách sửa 4

Một dòng use là một lối tắt. use rand::random_range; có nghĩa “từ giờ, random_range là thứ nằm ở rand::random_range”. Trước khi tạo được lối tắt đó, Rust phải đi theo đường dẫn từng đoạn một: trước hết tìm rand, rồi tìm random_range bên trong nó.

Dấu ^^^^ đánh dấu đoạn đầu tiên bị hỏng. Ở đây là rand, ngay đoạn đầu, nên Rust còn chưa kịp tìm random_range. Dòng help: đoán lý do: rand là một crate trên crates.io, và project này chưa thêm nó vào.

Giống như bạn đưa tài xế taxi địa chỉ “12 phố Bến Cảng, thành phố Springfeld”. Nếu tên thành phố sai, tài xế còn chẳng biết bắt đầu tìm con phố từ đâu.

Rust phân giải mọi đường dẫn lúc biên dịch, không phải lúc chương trình chạy. Không có gì được nạp “phòng khi cần”. Code của bạn chỉ nhìn thấy ba loại thứ: các crate liệt kê trong Cargo.toml (cộng với std), các module bạn khai báo bằng mod, và những gì bên trong chúng. Nếu một dòng use nêu tên thứ nằm ngoài tập đó, Rust dừng ngay thay vì đoán.

Đây là điều tốt. Một import gõ sai trong Python hay JavaScript thường chỉ lỗi khi dòng đó cuối cùng được chạy, có khi là lúc đã lên production. Trong Rust, nó thậm chí không build được. Điều đó cũng có nghĩa là một crate bạn chưa từng thêm vào sẽ không bao giờ lẻn được vào chương trình của bạn.

Từ edition 2018, một đường dẫn use bắt đầu ở một trong các chỗ sau: tên một crate (std, rand), crate (gốc của chính crate bạn), self (module hiện tại), super (module cha), hoặc một module được khai báo trong module hiện tại. Bài Module nói chi tiết về điều này, còn Cargo và crate giải thích về dependency.

Chọn cách này khi đoạn đầu tiên là một crate từ crates.io, như rand, serde hay regex, và dòng help: có nhắc tới cargo add. Đây là nguyên nhân phổ biến nhất, nhất là khi bạn chép code từ một bài blog. Chạy lệnh này trong thư mục chứa Cargo.toml:

Terminal window
cargo add rand

Cargo tìm phiên bản mới nhất và tự thêm một dòng vào Cargo.toml cho bạn:

[dependencies]
rand = "0.10.3"

Giờ thì cùng đoạn code đó build được. Phiên bản này in ra một phép kiểm tra thay vì chính con số tung được, để kết quả lúc nào cũng giống nhau:

use rand::random_range;
fn main() {
let roll = random_range(1..=6);
println!("Số tung được nằm trong khoảng 1 đến 6: {}", (1..=6).contains(&roll));
}

Kết quả:

Số tung được nằm trong khoảng 1 đến 6: true
▶ Tự chạy thử

Có hai điều hay làm người ta vấp. Thứ nhất, tên crate có dấu gạch ngang sẽ dùng dấu gạch dưới trong code: bạn chạy cargo add tracing-subscriber nhưng viết use tracing_subscriber::.... Thứ hai, nếu crate là dependency của workspace, nó vẫn phải được liệt kê trong Cargo.toml của package dùng nó.

Cách sửa 2: Sửa chính tả của đường dẫn

Phần tiêu đề “Cách sửa 2: Sửa chính tả của đường dẫn”

Chọn cách này khi nhãn ghi could not find `X` in `Y` hoặc no `X` in `Y`. Có gì đó ở giữa hoặc cuối đường dẫn bị viết sai. Một ví dụ kinh điển:

error[E0432]: unresolved import `std::collection`
--> src/main.rs:1:10
|
1 | use std::collection::HashMap;
| ^^^^^^^^^^ could not find `collection` in `std`

Rust không tìm thấy collection bên trong std. Module đúng là collections, có chữ s. Tên còn phân biệt chữ hoa chữ thường: use std::collections::Hashmap; lỗi với no `Hashmap` in `collections`, và rustc thêm help: a similar name exists in the module kèm cách viết đúng. Dòng import đã sửa:

use std::collections::HashMap;
fn main() {
let mut stock: HashMap<&str, u32> = HashMap::new();
stock.insert("táo", 12);
println!("{:?}", stock.get("táo"));
}

Kết quả:

Some(12)
▶ Tự chạy thử

Nếu không chắc đường dẫn chính xác, hãy tìm trong tài liệu thư viện chuẩn (tiếng Anh). Trang của mỗi mục đều ghi đường dẫn đầy đủ ở trên cùng. Xem HashMap để biết thêm về kiểu này.

Chọn cách này khi bạn vừa tạo một file mới, chẳng hạn src/inventory.rs, và use inventory::... không tìm thấy nó. Trong Rust, một file chưa phải là module cho tới khi một file cha khai báo nó. Project của bạn trông như thế này:

src/
├── main.rs use inventory::count_items; ← chưa có `mod inventory;`
└── inventory.rs pub fn count_items() -> u32 { 42 }

Và rustc nói chính xác thứ đang thiếu:

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;
|

Rust thấy file src/inventory.rs nhưng nó chưa được khai báo, và gợi ý thêm mod inventory;. Hãy thêm mod inventory; ở đầu src/main.rs (hoặc src/lib.rs, nếu module thuộc về thư viện của bạn). Viết use crate::inventory::count_items; thay vào đó không giúp được gì; nó lỗi với could not find `inventory` in the crate root, vì module vẫn chưa được khai báo.

Trên Playground mọi thứ nằm trong một file, nên ở đây module được viết trực tiếp bằng mod inventory { ... }. Nó hoạt động y hệt như file riêng:

mod inventory {
pub fn count_items() -> u32 {
42
}
}
use inventory::count_items;
fn main() {
println!("Số hàng trong kho: {}", count_items());
}

Kết quả:

Số hàng trong kho: 42
▶ Tự chạy thử

Khai báo mỗi module một lần, trong module cha của nó. Các file khác sau đó tới được nó bằng use crate::inventory::.... Đừng thêm mod inventory; vào mọi file dùng nó.

Cách sửa 4: Bắt đầu đường dẫn từ đúng chỗ

Phần tiêu đề “Cách sửa 4: Bắt đầu đường dẫn từ đúng chỗ”

Chọn cách này khi dòng import nằm trong một module và thứ cần import lại nằm ở một module khác trong chính crate của bạn. Ở đây receipt nằm trong shop và muốn dùng 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`

Chú thích // ❌ giữ tiếng Anh vì nó xuất hiện trong thông báo lỗi; nó nói rằng dòng này tìm sai chỗ. Một cái tên trơn ở đầu đường dẫn use có nghĩa “một crate, hoặc thứ gì đó được khai báo ngay trong module này”. store_name không phải cả hai, nên Rust đi tìm một crate có tên đó. Hãy nói cho nó biết phải bắt đầu từ đâu:

Tiền tố Bắt đầu từ Ví dụ
crate:: gốc của crate bạn (main.rs hoặc lib.rs) use crate::shop::prices::price_of;
super:: module cha use super::store_name;
self:: module hiện tại use self::lines::line;

Cả ba trong một chương trình:

mod shop {
pub fn store_name() -> &'static str {
"Ferris Fruits"
}
pub mod prices {
pub fn price_of(item: &str) -> u32 {
if item == "táo" { 3 } else { 5 }
}
}
pub mod receipt {
use super::store_name; // module cha: shop
use crate::shop::prices::price_of; // từ gốc của crate
use self::layout::line; // module con của module này
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("táo");
}

Kết quả:

== Ferris Fruits ==
táo: 3
▶ Tự chạy thử

Ở đây use layout::line; cũng chạy được, vì layout được khai báo trong module hiện tại; self:: chỉ làm điều đó rõ ràng hơn. Khi còn phân vân, crate:: với đường dẫn đầy đủ luôn dùng được từ bất kỳ đâu trong crate, và rustc thường gợi ý nó: help: a similar path exists theo sau là phiên bản crate::.

Code viết cho phiên bản crate cũ. Nhiều bài hướng dẫn dùng rand 0.8. Với rand 0.10 bạn sẽ gặp:

error[E0432]: unresolved import `rand::thread_rng`
--> src/main.rs:1:5
|
1 | use rand::thread_rng;
| ^^^^^^^^^^^^^^^^ no `thread_rng` in the root

Rust báo không có thread_rng ở gốc crate rand. Cách sửa: xem tài liệu của crate trên docs.rs cho đúng phiên bản trong Cargo.toml của bạn. Ở đây tên mới là rand::rng(). Xem Số ngẫu nhiên.

Một package có cả main.rs lẫn lib.rs. Đó là hai crate riêng biệt. Bên trong main.rs, crate:: nghĩa là crate binary, nên use crate::inventory::count_items; lỗi với could not find `inventory` in the crate root dù lib.rs có pub mod inventory;. Cách sửa: dùng tên package, use shop_app::inventory::count_items; (dấu gạch ngang đổi thành gạch dưới).

Thứ cần import có tồn tại nhưng là riêng tư (private). Đó là một lỗi khác, E0603, không phải E0432:

error[E0603]: function `count_items` is private
--> src/main.rs:7:16
|
7 | use inventory::count_items;
| ^^^^^^^^^^^ private function

Cách sửa: thêm pub trước fn (và trước mọi mod trên đường đi, vì một module riêng tư sẽ cho ra module `prices` is private). Xem Module.

  • E0433: một đường dẫn bên trong code (như HashMap::new() hay rand::rng()) không phân giải được. Cùng nguyên nhân, nhưng không nằm trên dòng use.
  • E0425: không tìm thấy giá trị hoặc hàm, thường được sửa bằng chính dòng use đó.
  • E0603: đã tìm thấy thứ cần import nhưng nó là riêng tư. Hãy thêm pub.
  • E0463: can't find crate, lỗi bạn gặp với extern crate rand; khi crate chưa có trong Cargo.toml.
  • Tất cả lỗi trình biên dịch: danh sách đầy đủ các trang lỗi.

Kiểm tra nhanh

1. Bạn chép use serde::Serialize; vào một project mới và gặp E0432 nói rằng crate serde chưa được phân giải hoặc chưa liên kết. Cách sửa là gì?

2. Bạn đã tạo src/billing.rs, nhưng use billing::total; trong main.rs bị lỗi. Còn thiếu gì?

3. Bên trong mod shop { mod receipt { ... } }, receipt import một hàm được định nghĩa trực tiếp trong shop như thế nào?

Điểm: 0 / 3