Rust的模块系统实际上是非常灵活的,可以让您在隐藏代码在文件中的结构时公开所需的任何类型的结构。
我认为这里的关键是利用pub use
,这将允许您从其他模块中重新导出标识符。Rust的std::io
板条箱中有此先例,其中子模块中的某些类型被重新导出以用于中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书中的“包装箱和模块”一章非常好。有很多例子。
最后,Rust编译器还会自动为您查找子目录。例如,以上代码在此目录结构下将保持不变:
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
编译和运行的命令也保持不变。