Lỗi Rust E0433: failed to resolve, use of undeclared type (kiểu chưa khai báo)
E0433 nghĩa là bạn viết một đường dẫn như HashMap::new() hay rand::rng(), và Rust không biết phần đầu tiên của nó là gì. Gần như lúc nào cũng chỉ thiếu một dòng: một use, một dependency trong Cargo.toml, hoặc một khai báo mod. Tin vui là rustc thường in sẵn đúng dòng đó cho bạn chép. Trang này thuộc hướng dẫn về lỗi trình biên dịch.
Thông báo lỗi
Phần tiêu đề “Thông báo lỗi”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; |Trình biên dịch báo rằng nó không tìm thấy kiểu HashMap trong phạm vi này, và gợi ý import nó từ std::collections.
Đây là chương trình gây ra lỗi:
fn main() { let mut stock = HashMap::new(); stock.insert("apples", 12); println!("{:?}", stock.get("apples"));}Các phiên bản Rust cũ hơn in cùng lỗi này dưới dạng “failed to resolve: use of undeclared type HashMap”. Tùy thứ bị thiếu, nhãn cũng có thể ghi use of unresolved module or unlinked crate (cho một crate hoặc module) thay vì use of undeclared type. Tất cả đều là E0433, và đều được sửa theo cùng một cách.
Ý nghĩa
Phần tiêu đề “Ý nghĩa”Dấu ^^^^^^^ chỉ vào HashMap, phần trước dấu ::. Để gọi HashMap::new(), Rust phải tìm ra thứ gì đó tên là HashMap trước đã. Nó đã xem mọi thứ nhìn thấy được từ dòng 2 và không tìm thấy gì có tên đó, nên nó còn chưa thể bắt đầu tìm new.
Dòng help: là phần quan trọng. rustc đã tìm trong thư viện chuẩn, thấy một struct tên HashMap trong std::collections, và cho bạn dòng use giúp nó hiện ra. 1 + nghĩa là “thêm dòng này làm dòng 1”.
Giống như bạn hỏi thủ thư “chương 3 của cuốn đó” mà không nói là cuốn nào. Họ biết có rất nhiều cuốn sách có chương 3, nhưng họ cần biết tên sách trước đã.
Vì sao Rust làm vậy
Phần tiêu đề “Vì sao Rust làm vậy”Chỉ một nhóm nhỏ tên tự động hiện diện trong mọi file Rust. Nhóm này gọi là prelude: Vec, String, Option, Some, None, Result, Ok, Err, Box và vài trait. Mọi thứ khác, kể cả HashMap, HashSet, fs và Ordering, đều phải được đưa vào bằng use hoặc viết bằng đường dẫn đầy đủ.
Nhờ vậy prelude gọn nhẹ và tránh được trùng tên. Ví dụ, thư viện chuẩn có hai kiểu Ordering khác nhau, và code của bạn cũng có thể có một Duration hay một Result riêng. Rust sẽ không đoán bạn muốn cái nào. Bạn nói một lần ở đầu file, và ai đọc cũng thấy mỗi cái tên đến từ đâu.
Crate và module cũng vậy: một crate chỉ tồn tại với code của bạn sau khi nó được liệt kê trong Cargo.toml, và một module chỉ tồn tại sau một dòng mod. Xem Module và Cargo và crate.
Cách sửa
Phần tiêu đề “Cách sửa”Cách sửa 1: Thêm dòng use mà rustc gợi ý
Phần tiêu đề “Cách sửa 1: Thêm dòng use mà rustc gợi ý”Chọn cách này khi dòng help: ghi consider importing. Đây là cách sửa phổ biến nhất, bỏ xa các cách khác. Chép dòng được gợi ý lên đầu file:
use std::collections::HashMap;
fn main() { let mut stock = HashMap::new(); stock.insert("táo", 12); println!("{:?}", stock.get("táo"));}Kết quả:
Some(12)Lựa chọn còn lại là viết đường dẫn đầy đủ ở chỗ gọi, std::collections::HashMap::new(). Cách đó cũng chạy được, nhưng bạn sẽ phải lặp lại nó ở khắp nơi, nên một dòng use là lựa chọn bình thường. Đọc thêm về kiểu này ở HashMap.
Nếu rustc đưa ra nhiều dòng import (consider importing one of these), hãy đọc kỹ trước khi chọn. Đó là các kiểu khác nhau trùng tên, và chỉ một trong số đó là thứ bạn muốn.
Cách sửa 2: Sửa tên kiểu, hoặc khai báo kiểu
Phần tiêu đề “Cách sửa 2: Sửa tên kiểu, hoặc khai báo kiểu”Chọn cách này khi cái tên là kiểu của chính bạn. Nếu không có dòng help: nào, kiểu đó chưa tồn tại; nếu có lỗi gõ nhầm, rustc chỉ ra cái tên gần giống:
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(); | +Dấu + dưới dòng code cho thấy chữ cái bị thiếu. Hãy sửa chính tả:
struct Inventory { items: Vec<String>,}
impl Inventory { fn new() -> Self { Inventory { items: Vec::new() } }}
fn main() { let stock = Inventory::new(); println!("{} món hàng", stock.items.len());}Kết quả:
0 món hàngNếu Order::new() gây E0433 mà không có gợi ý nào, nghĩa là bạn chưa viết struct Order (hoặc nó nằm trong một file bạn chưa khai báo bằng mod). Cũng hãy kiểm tra chữ hoa: inventory::new() và Inventory::new() là hai cái tên khác nhau.
Cách sửa 3: Nêu tên module chứa kiểu đó
Phần tiêu đề “Cách sửa 3: Nêu tên module chứa kiểu đó”Chọn cách này khi kiểu hoặc enum được định nghĩa bên trong một module và bạn dùng nó từ bên ngoài. Ở đây enum nằm trong mod traffic, nhưng main lại viết 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; |Hãy import enum (hoặc viết traffic::Light::Green). Lưu ý rằng bạn import enum, rồi vẫn viết Light::Green cho từng biến thể (variant):
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:?}: được đi = {}", can_go(&now));}Kết quả:
Green: được đi = trueĐường dẫn tới một biến thể có đúng hai phần: Enum::Variant. Nếu bạn viết dư một phần, như Light::Red::Green, bạn sẽ gặp E0433 với cannot find module `Red` in `Light` và nhãn `Red` is a variant, not a module (Red là biến thể, không phải module). Xem Enum.
Cách sửa 4: Thêm crate, hoặc khai báo module
Phần tiêu đề “Cách sửa 4: Thêm crate, hoặc khai báo module”Chọn cách này khi nhãn ghi use of unresolved module or unlinked crate. Phần đầu của đường dẫn là một crate hoặc module mà Rust không biết tới:
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`Với một crate từ crates.io, hãy chạy cargo add rand trong thư mục project. Với một module của thư viện chuẩn như fs, rustc sẽ gợi ý use std::fs;. Còn với file của chính bạn, chẳng hạn src/inventory.rs, dòng help ghi to make use of source file src/inventory.rs, use `mod inventory` in this file to declare the module (để dùng file nguồn src/inventory.rs, hãy khai báo module bằng mod inventory trong file này):
src/├── main.rs inventory::count_items() ← cần `mod inventory;` ở đầu file└── inventory.rs pub fn count_items() -> u32 { 42 }Đây là cùng chương trình đó trong một file, với module viết trực tiếp để chạy được trên Playground:
mod inventory { pub fn count_items() -> u32 { 42 }}
fn main() { println!("Số hàng trong kho: {}", inventory::count_items());}Kết quả:
Số hàng trong kho: 42Với file riêng, thay đổi duy nhất là mod inventory { ... } trở thành mod inventory; và phần thân chuyển sang src/inventory.rs.
Còn extern crate thì sao?
Phần tiêu đề “Còn extern crate thì sao?”Bạn có thể thấy extern crate rand; trong code cũ. Từ edition 2018 bạn không cần nó nữa: một khi crate đã có trong Cargo.toml, bạn dùng được nó ngay. Thêm extern crate không sửa được E0433. Nếu thiếu dependency, nó chỉ đổi lỗi thành E0463, can't find crate for rand. cargo add mới là cách sửa thật sự.
Thường gặp ở đâu
Phần tiêu đề “Thường gặp ở đâu”So sánh bằng cmp. match a.cmp(&b) với các nhánh Ordering::Less gây E0433, và rustc gợi ý hai dòng import: use std::cmp::Ordering; và use std::sync::atomic::Ordering;. Bạn cần std::cmp::Ordering; cái atomic là dành cho luồng. Xem Match.
Test trong khối mod tests. Một module test là module con, nên nó không nhìn thấy các kiểu của bạn nếu không import. Inventory::new() bên trong mod tests gây E0433 với help: consider importing this struct và use crate::Inventory;. Cách sửa: đặt use super::*; ở đầu module test. Xem Kiểm thử.
Code dán từ tài liệu hoặc bài blog. Ví dụ thường bỏ qua các dòng use. fs::read_to_string(...) lỗi với cannot find module or crate `fs` in this scope kèm help use std::fs;. Cách sửa: thêm dòng import mà rustc đưa ra, hoặc tra đường dẫn của mục đó trên trang tài liệu của nó.
Lỗi liên quan
Phần tiêu đề “Lỗi liên quan”- E0432: cùng kiểu vấn đề nhưng trên một dòng
use,unresolved import. - E0425: không tìm thấy một giá trị hoặc hàm (không có
::), như một biến bị gõ nhầm. rustc hiện tại cũng dùng E0425 cho kiểu bị thiếu ở vị trí kiểu, nhưlet m: HashMap<&str, u32>; các phiên bản cũ gọi đó là E0412. Cùng một dòngusesửa được nó. - E0599: đã tìm thấy kiểu, nhưng phương thức hoặc biến thể sau
::không tồn tại, nhưLight::Blue. - E0463:
can't find crate, doextern cratemà không có dependency. - Tất cả lỗi trình biên dịch: danh sách đầy đủ các trang lỗi.
Kiểm tra nhanh
Phần tiêu đề “Kiểm tra nhanh”Kiểm tra nhanh
1. Vì sao HashSet::new() gây E0433 trong khi Vec::new() chạy được mà không cần import gì?
2. rustc gợi ý cả use std::cmp::Ordering; lẫn use std::sync::atomic::Ordering; cho match a.cmp(&b) của bạn. Bạn chọn cái nào?
3. rand::rng() gây E0433 với nhãn 'use of unresolved module or unlinked crate'. Cách nào sửa được?
Điểm: 0 / 3
Đọc thêm
Phần tiêu đề “Đọc thêm”- E0433 — Rust error codes index (tiếng Anh): giải thích chính thức, với trường hợp kiểu chưa khai báo và crate chưa liên kết.
- Bringing Paths into Scope with the
useKeyword — The Rust Book (tiếng Anh):usehoạt động thế nào, và vì sao import các kiểu nhưHashMaplà chuyện bình thường. - Paths for Referring to an Item in the Module Tree — The Rust Book (tiếng Anh): đường dẫn đầy đủ,
crate::vàsuper::. std::prelude— tài liệu thư viện chuẩn (tiếng Anh): danh sách chính xác những tên nhìn thấy được mà không cầnuse.- Path and module changes in Rust 2018 — Edition Guide (tiếng Anh): vì sao không còn cần
extern crate.