blog.dopana

Back

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:

  1. 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.
  2. 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.
  3. 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).
  4. 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ĩaQuy ước đặt file
PackageMộ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
CrateMộ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)
ModuleTổ 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
PathCá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#

[!NOTE] Khai báo pub mod chỉ 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ằng pub.

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 struct chỉ 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 enum sẽ tự động công khai tất cả các variant bên trong nó.

Đư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):

sequenceDiagram
    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:

src/lib.rs
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;
rust

Tá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.rs
text
src/lib.rs
// 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
src/front_of_house.rs
// Khai báo submodule hosting; Rust tự tìm src/front_of_house/hosting.rs
pub mod hosting;
rust
src/front_of_house/hosting.rs
pub fn add_to_waitlist() {
    println!("Đã thêm khách vào hàng đợi!");
}
rust

Tổ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.

Tài liệu tham khảo#