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

Lỗi Rust E0601: `main` function not found in crate (thiếu hàm main)

E0601 nghĩa là: Rust muốn build một chương trình, nhưng không tìm thấy chỗ bắt đầu của nó. Mọi chương trình Rust đều bắt đầu trong một hàm có tên chính xác là main, được viết ở cấp cao nhất của src/main.rs. Nếu nó bị thiếu, bị gõ sai, hoặc bị nhét vào trong một module, bạn sẽ gặp lỗi này. Lỗi này rất hay gặp khi bạn chép một đoạn code từ bài hướng dẫn hay tài liệu của một thư viện, và lúc nào cũng sửa nhanh. (Trang này thuộc loạt bài Giải thích các lỗi trình biên dịch Rust.)

error[E0601]: `main` function not found in crate `main`
--> src/main.rs:7:2
|
7 | } // ❌ end of the file, and no `fn main` anywhere
| ^ consider adding a `main` function to `src/main.rs`

Thông báo của trình biên dịch luôn bằng tiếng Anh: “main function not found in crate main” nghĩa là “không tìm thấy hàm main trong crate main”. Đây là chương trình gây ra lỗi đó (chú thích được giữ bằng tiếng Anh vì nó xuất hiện nguyên văn trong thông báo lỗi):

fn total(prices: &[u32]) -> u32 {
prices.iter().sum()
}
fn average(prices: &[u32]) -> u32 {
total(prices) / prices.len() as u32
} // ❌ end of the file, and no `fn main` anywhere

Dấu ^ chỉ vào ngay cuối file, ngay sau dấu } cuối cùng. Trông thì lạ, nhưng hợp lý: rustc đã đọc hết file để tìm fn main, và tới cuối file mà không thấy. Không có dòng sai nào để chỉ vào; vấn đề là một dòng không hề tồn tại.

Tên crate trong thông báo phụ thuộc vào cách bạn build. Kết quả trên đến từ rustc src/main.rs, nên crate được đặt tên là main, theo tên file. Với cargo run, bạn sẽ thấy tên package trong Cargo.toml, ví dụ `main` function not found in crate `shop`. Cùng một lỗi, cùng cách sửa.

Giống như một kịch bản có những cảnh rất hay nhưng không có “Hồi 1, Cảnh 1”. Diễn viên đã sẵn sàng, nhưng chẳng ai biết vở diễn bắt đầu từ đâu.

Một binary Rust (chương trình bạn chạy được) cần một điểm vào (entry point) cố định. Khi bạn khởi động chương trình, hệ điều hành gọi main, và mọi thứ khác diễn ra vì main gọi tới chúng. Rust không đoán: không phải hàm đầu tiên trong file, không phải hàm tên start, không phải Main. Tên phải chính xác là main, viết thường hoàn toàn, ở cấp cao nhất của crate.

Code không tự chạy được như một chương trình, như một bộ hàm hỗ trợ cho code khác dùng, là một thư viện (library). Thư viện không có main và được viết trong src/lib.rs. E0601 thường có nghĩa là code vẫn ổn, chỉ là nằm sai loại crate. Xem Crate binary và library cùng nhau và Bắt đầu.

Cách sửa 1: Thêm hàm main (hoặc sửa chính tả của nó)

Phần tiêu đề “Cách sửa 1: Thêm hàm main (hoặc sửa chính tả của nó)”

Phần lớn trường hợp, hãy chọn cách này: bạn đã chép các hàm từ đâu đó, hoặc bạn bắt đầu gõ các hàm hỗ trợ mà chưa viết main. Thêm fn main() và gọi code của bạn từ đó:

fn total(prices: &[u32]) -> u32 {
prices.iter().sum()
}
fn average(prices: &[u32]) -> u32 {
total(prices) / prices.len() as u32
}
fn main() { // ✅ chương trình bắt đầu từ đây
let prices = [250, 199, 1200];
println!("tổng: {} xu", total(&prices));
println!("trung bình: {} xu", average(&prices));
}

Kết quả:

tổng: 1649 xu
trung bình: 549 xu
▶ Tự chạy thử

Đã có main rồi? Vậy hãy kiểm tra chính tả. fn Main(), fn mian() hay fn main_() đều gây ra đúng lỗi E0601 đó, vì với Rust chúng chỉ là những hàm khác. Tên phân biệt chữ hoa chữ thường, và nó phải là một hàm: fn main(), có cặp ngoặc tròn.

Chọn cách này khi thông báo nói the main function must be defined at the crate level (hàm main phải được định nghĩa ở cấp crate). Bạn có main, nhưng nó nằm trong một mod, nên thật ra nó là app::main, không phải điểm vào của chương trình:

error[E0601]: `main` function not found in crate `main`
--> src/main.rs:5:2
|
5 | }
| ^ the main function must be defined at the crate level (in `src/main.rs`)
|
note: here is a function named `main`
--> src/main.rs:2:5
|
2 | pub fn main() { // ❌ inside a module, not at the top level
| ^^^^^^^^^^^^^
= note: you have one or more functions named `main` not defined at the crate level
= help: consider moving the `main` function definitions

Chương trình đằng sau lỗi này:

mod app {
pub fn main() { // ❌ inside a module, not at the top level
println!("Starting the shop...");
}
}

Đặt main thật ở cấp cao nhất. Code trong module có thể giữ nguyên ở đó; hãy đặt cho nó một cái tên rõ hơn như run và gọi nó từ main:

mod app {
pub fn run() {
println!("Đang mở cửa hàng...");
}
}
fn main() { // ✅ ở cấp cao nhất của src/main.rs
app::run();
}

Kết quả:

Đang mở cửa hàng...
▶ Tự chạy thử

Module ở file khác cũng vậy: một pub fn main() trong src/app.rs là app::main, không bao giờ là điểm vào. Xem Module.

Cách sửa 3: Biến nó thành thư viện, nếu nó không dùng để tự chạy

Phần tiêu đề “Cách sửa 3: Biến nó thành thư viện, nếu nó không dùng để tự chạy”

Chọn cách này khi code là một bộ hàm hỗ trợ cho code khác dùng, chẳng có gì để “chạy”. Thư viện không có main. Tạo dự án với --lib:

Terminal window
cargo new --lib cart # creates src/lib.rs: a library, no main needed
cargo new shop # creates src/main.rs with fn main(): a program

Lệnh thứ nhất tạo một thư viện (src/lib.rs, không cần main), lệnh thứ hai tạo một chương trình (src/main.rs có sẵn fn main()). Đặt các hàm hỗ trợ vào src/lib.rs, đánh dấu pub cho những gì code khác được dùng, và kiểm tra chúng bằng test thay vì cargo run:

src/lib.rs
pub fn total(prices: &[u32]) -> u32 {
prices.iter().sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn adds_prices() {
assert_eq!(total(&[3, 4]), 7);
}
}

Với thư viện, hãy chạy cargo build hoặc cargo test. cargo run không dùng được ở đó; nó báo error: a bin target must be available for `cargo run`, cách Cargo nói rằng “package này không có chương trình nào”. Nếu bạn muốn có cả hai, hãy thêm một src/main.rs bên cạnh src/lib.rs. Nó dùng thư viện qua tên package:

src/main.rs
fn main() {
let sum = cart::total(&[250, 199, 1200]);
println!("total: {} cents", sum);
}

Giờ cargo run in ra total: 1649 cents. Xem Crate binary và library cùng nhau và Kiểm thử.

Dán một đoạn code từ tài liệu hoặc bài hướng dẫn. Nhiều ví dụ chỉ cho thấy một hàm hoặc một struct, không phải cả chương trình. Dán vào src/main.rs, chúng gây ra E0601. Cách sửa: bọc những dòng thực hiện việc gì đó trong fn main() { ... }, còn hàm và struct thì để bên ngoài. (Rust Playground nhận ra việc thiếu main và đề nghị build code thay vì chạy, nên ở đó bạn thường không thấy lỗi này.)

Editor tô đỏ dòng cuối của main.rs. rust-analyzer chạy cargo check ở chế độ nền, nên bạn thấy E0601 ở dòng cuối trong lúc vẫn đang viết các hàm hỗ trợ. Không sao cả: dấu đỏ biến mất ngay khi bạn thêm fn main().

Chương trình phụ trong src/bin/. Mỗi file trong src/bin/, như src/bin/import.rs, là một chương trình riêng, và mỗi file cần fn main() của riêng nó. Cách sửa: thêm main vào file đó, hoặc chuyển code dùng chung vào src/lib.rs. Xem đường dẫn Cargo Targets ở cuối trang.

Kiểm tra nhanh

1. src/main.rs của bạn có fn Main() { ... }. cargo run sẽ nói gì?

2. Bạn đang viết các hàm hỗ trợ cho code khác dùng, chẳng có gì để chạy. Cách tổ chức đúng là gì?

3. rustc nói “the main function must be defined at the crate level”. Có gì sai?

Điểm: 0 / 3