Hệ thống Module trong Rust: Packages, Crates và Modules
Làm chủ hệ thống Module trong Rust: Packages, Crates, Modules, phạm vi truy cập (pub), và từ khóa use giúp tổ chức dự án chuyên nghiệp.
Khi dự án Rust bắt đầu mở rộng vượt ra ngoài một file mã nguồn đơn lẻ, việc tổ chức cấu trúc code trở nên vô cùng quan trọng. Rust cung cấp một hệ thống module chặt chẽ giúp cân bằng giữa tính đóng gói (encapsulation), bảo mật phạm vi truy cập (privacy) và khả năng tái sử dụng.
Explain Like I’m 10: Nhà Máy Đồ Chơi & Các Phân Xưởng#
Hãy tưởng tượng việc xây dựng một nhà máy sản xuất đồ chơi:
- Package (
Cargo.toml): Toàn bộ khuôn viên nhà máy, bao gồm tài liệu hướng dẫn lắp ráp, hóa đơn nguyên vật liệu và bản vẽ xây dựng. - Crate (Thư viện gốc / File thực thi): Một container hàng hoàn chỉnh sẵn sàng giao đến tay khách hàng hoặc chuyển đến các nhà máy đối tác.
- Module (
mod): Từng phòng ban, phân xưởng bên trong nhà máy (như: Xưởng chế tác gỗ, Xưởng phun sơn, Ban kiểm định chất lượng). - Phạm vi bảo mật (
pub): Cửa khóa nội bộ (private) so với quầy tiếp tân mở cửa đón khách (pub). Mặc định trong Rust, mọi cánh cửa đều bị khóa để người ngoài không thể tự ý thao tác vào máy móc bên trong.
graph TD
subgraph Package ["Package (Cargo.toml)"]
subgraph BinaryCrate ["Binary Crate (src/main.rs)"]
MainFn["main() entry point"]
end
subgraph LibraryCrate ["Library Crate (src/lib.rs)"]
RootMod["Crate Root (crate::)"]
RootMod --> ModFront["mod front_of_house"]
ModFront --> ModHosting["pub mod hosting"]
ModHosting --> FnAdd["pub fn add_to_waitlist()"]
RootMod --> ModBack["mod back_of_house"]
ModBack --> FnCook["fn fix_incorrect_order()"]
end
end
MainFn -->|use restaurant::front_of_house::hosting| FnAdd
Cấp Bậc Kiến Trúc: Packages, Crates và Modules#
| Cấp bậc | Định nghĩa | Quy ước đặt file |
|---|---|---|
| Package | Một gói Cargo chứa file Cargo.toml mô tả cách biên dịch một hoặc nhiều crate. | Thư mục gốc chứa file Cargo.toml |
| Crate | Một cây module sinh ra thư viện dùng chung (library) hoặc tệp chạy thực thi (binary). | src/main.rs (binary) hoặc src/lib.rs (library) |
| Module | Tổ chức phạm vi code và kiểm soát tính riêng tư của các thành phần trong crate. | Inline mod tên { ... } hoặc src/tên.rs / src/tên/mod.rs |
| Path | Cách đặt tên định tuyến tới một mục (struct, hàm hoặc module). | crate::front_of_house::hosting::add_to_waitlist() |
Quy Tắc Phạm Vi Truy Cập (Privacy Rules)#
Trong Rust, tất cả các thành phần (hàm, method, struct, enum, module con) mặc định đều ở trạng thái private đối với module cha.
graph LR
Parent["Module Cha"] -->|Có thể thấy mọi thứ bên trong| Child["Module Con"]
Child -->|Không thể thấy hàm private ngang hàng trừ khi pub| Sibling["Thành Phần Ngang Hàng"]
Child -->|Luôn thấy mọi thành phần ở module cha| Parent
Ví Dụ Về Quản Lý Nhà Hàng#
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
fn seat_at_table() {} // private: chỉ truy cập được bên trong hosting
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
pub fn eat_at_restaurant() {
// Đường dẫn tuyệt đối bắt đầu từ gốc crate
crate::front_of_house::hosting::add_to_waitlist();
// Đường dẫn tương đối từ vị trí module hiện tại
front_of_house::hosting::add_to_waitlist();
}rust[!NOTE] Khai báo
pub modchỉ cho phép module cha gọi tới bản thân module đó. Các hàm và trường bên trong nó vẫn giữ nguyên trạng thái private cho tới khi bạn đánh dấu tường minh bằngpub.
Sự Khác Biệt Giữa Struct và Enum Khi Dùng pub#
Cách hoạt động của từ khóa pub có sự khác biệt rõ rệt giữa struct và enum:
- Structs: Đặt
pub structchỉ công khai tên struct, nhưng các trường (fields) bên trong mặc định vẫn là private trừ khi từng trường được gắn tiền tốpub. - Enums: Đặt
pub enumsẽ tự động công khai tất cả các variant bên trong nó.
mod back_of_house {
pub struct Breakfast {
pub toast: String, // Trường public: khách hàng có thể tự chọn loại bánh mì
seasonal_fruit: String, // Trường private: đầu bếp chọn loại trái cây theo mùa
}
impl Breakfast {
// Vì seasonal_fruit là private, bắt buộc phải cung cấp constructor public
pub fn summer(toast: &str) -> Breakfast {
Breakfast {
toast: String::from(toast),
seasonal_fruit: String::from("peaches"),
}
}
}
#[derive(Debug)]
pub enum Appetizer {
Soup, // Tự động là public
Salad, // Tự động là public
}
}rustĐưa Đường Dẫn Vào Phạm Vi Với use#
Việc viết đi viết lại đường dẫn dài sẽ làm code bị rối. Từ khóa use mang đường dẫn vào scope hiện tại tương tự như một liên kết mềm (symbolic link):
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// Đưa module vào scope theo quy ước chuẩn của Rust cho hàm
use crate::front_of_house::hosting;
// Đưa struct/enum trực tiếp vào scope
use std::collections::HashMap;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
let mut map = HashMap::new();
map.insert("bàn_1", "đã_đặt");
}rustsequenceDiagram
participant Code as Đoạn Mã Gọi
participant Scope as Local Scope Hiện Tại
participant CrateTree as Cây Module Crate
Note over Scope,CrateTree: use crate::front_of_house::hosting;
Scope->>CrateTree: Định tuyến đường dẫn tới module hosting
CrateTree-->>Scope: Tạo bí danh hosting trong scope hiện tại
Code->>Scope: hosting::add_to_waitlist()
Scope->>CrateTree: Thực thi front_of_house::hosting::add_to_waitlist()
Tái Xuất Bản (Re-exporting) Với pub use#
Khi dùng use, định danh mới chỉ có hiệu lực private trong scope hiện tại. Dùng pub use giúp công khai lại định danh đó ra bên ngoài, giúp thiết kế API công khai gọn gàng cho thư viện:
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
// Re-exporting: Người dùng bên ngoài có thể gọi trực tiếp restaurant::hosting::add_to_waitlist()
pub use crate::front_of_house::hosting;rustTách Module Ra Nhiều File Riêng Biệt#
Trong các dự án thực tế, mã nguồn được chia nhỏ theo cấu trúc thư mục hệ thống:
my_project/
├── Cargo.toml
└── src/
├── main.rs
├── lib.rs
└── front_of_house/
├── mod.rs (hoặc front_of_house.rs)
└── hosting.rstext// Khai báo module front_of_house; Rust tự tìm src/front_of_house.rs
pub mod front_of_house;
pub use crate::front_of_house::hosting;rust// Khai báo submodule hosting; Rust tự tìm src/front_of_house/hosting.rs
pub mod hosting;rustpub fn add_to_waitlist() {
println!("Đã thêm khách vào hàng đợi!");
}rustTổng kết#
- Packages đóng gói một hoặc nhiều crate được cấu hình qua
Cargo.toml. - Crates là đơn vị biên dịch sinh ra file thực thi (binary) hoặc thư viện (library).
- Modules (
mod) tổ chức mã nguồn theo không gian phân cấp và quản lý quyền truy cập. - Mọi thành phần đều private theo mặc định; sử dụng
pubđể công khai module, hàm và struct. - Dùng
useđể viết ngắn gọn vàpub useđể tái xuất bản API thư viện chuẩn mực.