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
が2つの異なるファイルの2つの異なるモジュールで定義されているという事実は完全に不透明です。
と同じディレクトリにいる場合は、次のコマンドでmain.rs
実行できます。
rustc src/lib.rs
rustc -L . main.rs
./main
一般的に、Rustブックの「クレートとモジュール」の章はかなり良いです。多くの例があります。
最後に、Rustコンパイラは自動的にサブディレクトリも検索します。たとえば、上記のコードは次のディレクトリ構造で変更せずに機能します。
src/
lib.rs
vector/
mod.rs
vector_b.rs
main.rs
コンパイルして実行するコマンドも同じです。