Rust 的模块系统实际上非常灵活,可以让您公开所需的任何类型的结构,同时隐藏代码在文件中的结构。
我认为这里的关键是使用pub use,这将允许您从其他模块重新导出标识符。在 Rust 的 std::io crate 中有这样的先例,其中子模块中的某些类型是 re-exported for use in std::io。
编辑(2019-08-25):答案的以下部分是很久以前写的。它解释了如何单独使用rustc 设置这样的模块结构。今天,人们通常会在大多数用例中使用 Cargo。虽然以下内容仍然有效,但其中的某些部分(例如#![crate_type = ...])可能看起来很奇怪。这不是推荐的解决方案。
为了适应你的例子,我们可以从这个目录结构开始:
src/
lib.rs
vector.rs
main.rs
这是你的main.rs:
extern crate math;
use math::vector;
fn main() {
println!("{:?}", vector::VectorA::new());
println!("{:?}", vector::VectorB::new());
}
还有你的src/lib.rs:
#[crate_id = "math"];
#[crate_type = "lib"];
pub mod vector; // exports the module defined in vector.rs
最后,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![] }
}
}
}
这就是魔法发生的地方。我们定义了一个子模块math::vector::vector_a,它实现了一种特殊的向量。但是我们不希望您图书馆的客户关心有一个vector_a 子模块。相反,我们希望在 math::vector 模块中提供它。这是通过pub use self::vector_a::VectorA 完成的,它在当前模块中重新导出vector_a::VectorA 标识符。
但是您询问了如何执行此操作,以便可以将您的特殊向量实现放在不同的文件中。这就是mod vector_b; 行的作用。它指示 Rust 编译器为该模块的实现查找 vector_b.rs 文件。果然,这是我们的src/vector_b.rs 文件:
#[derive(Debug)]
pub struct VectorB {
xs: Vec<i64>,
}
impl VectorB {
pub fn new() -> VectorB {
VectorB { xs: vec![] }
}
}
从客户端的角度来看,VectorA 和 VectorB 在两个不同文件中的两个不同模块中定义的事实是完全不透明的。
如果你和main.rs在同一个目录下,你应该可以运行它:
rustc src/lib.rs
rustc -L . main.rs
./main
总的来说,Rust 书中的"Crates and Modules" chapter 还是不错的。例子很多。
最后,Rust 编译器还会自动为您查找子目录。例如,上面的代码将在此目录结构下保持不变:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
编译和运行的命令也保持不变。