Hệ thống mô-đun của Rust thực sự cực kỳ linh hoạt và sẽ cho phép bạn hiển thị bất kỳ loại cấu trúc nào bạn muốn trong khi ẩn cách mã của bạn được cấu trúc trong tệp.
Tôi nghĩ chìa khóa ở đây là tận dụng pub use
, điều này sẽ cho phép bạn xuất lại số nhận dạng từ các mô-đun khác. Đã có tiền lệ cho điều này trong std::io
thùng của Rust nơi một số loại từ các mô-đun con được tái xuất để sử dụngstd::io
.
Chỉnh sửa (2019-08-25): phần sau của câu trả lời đã được viết cách đây khá lâu. Nó giải thích cách thiết lập cấu trúc mô-đun như vậy với rustc
một mình. Ngày nay, người ta thường sử dụng Cargo cho hầu hết các trường hợp sử dụng. Trong khi điều sau đây vẫn còn hiệu lực, một số phần của nó (ví dụ #![crate_type = ...]
) có thể có vẻ lạ. Đây không phải là giải pháp được khuyến nghị.
Để điều chỉnh ví dụ của bạn, chúng tôi có thể bắt đầu với cấu trúc thư mục này:
src/
lib.rs
vector.rs
main.rs
Đây là của bạn main.rs
:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
Và của bạn src/lib.rs
:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
Và cuối cùng, src/vector.rs
:
// exports identifiers from private sub-modules in the current
// module namespace
pub use self::vector_a::VectorA;
pub use self::vector_b::VectorB;
mod vector_b; // private sub-module defined in vector_b.rs
mod vector_a { // private sub-module defined in place
#[derive(Debug)]
pub struct VectorA {
xs: Vec<i64>,
}
impl VectorA {
pub fn new() -> VectorA {
VectorA { xs: vec![] }
}
}
}
Và đây là nơi điều kỳ diệu xảy ra. Chúng tôi đã xác định một mô-đun math::vector::vector_a
con có một số triển khai của một loại vectơ đặc biệt. Nhưng chúng tôi không muốn khách hàng của thư viện của bạn quan tâm rằng có một vector_a
mô-đun con. Thay vào đó, chúng tôi muốn cung cấp nó trong math::vector
mô-đun. Điều này được thực hiện với pub use self::vector_a::VectorA
, xuất lại mã vector_a::VectorA
định danh trong mô-đun hiện tại.
Nhưng bạn đã hỏi cách thực hiện điều này để bạn có thể đặt các triển khai vectơ đặc biệt của mình trong các tệp khác nhau. Đây là những gì mod vector_b;
dòng làm. Nó hướng dẫn trình biên dịch Rust tìm kiếm một vector_b.rs
tệp để triển khai mô-đun đó. Và chắc chắn, đây là src/vector_b.rs
tệp của chúng tôi :
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
Từ quan điểm của khách hàng, thực tế là VectorA
và VectorB
được xác định trong hai mô-đun khác nhau trong hai tệp khác nhau là hoàn toàn không rõ ràng.
Nếu bạn đang ở trong cùng một thư mục với main.rs
, bạn sẽ có thể chạy nó với:
rustc src/lib.rs
rustc -L . main.rs
./main
Nhìn chung, chương "Crates and Modules" trong sách Rust khá hay. Có rất nhiều ví dụ.
Cuối cùng, trình biên dịch Rust cũng tự động tìm kiếm trong các thư mục con cho bạn. Ví dụ, đoạn mã trên sẽ hoạt động không thay đổi với cấu trúc thư mục này:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
Các lệnh để biên dịch và chạy vẫn như cũ.