rust: クレート、パッケージ、モジュール
最終更新日: 2025/07/06
概要
プログラムを複数のファイルに分割したときの取り扱い方について。
Cargoを使う前提とする。
参考
- 肥大化していくプロジェクトをパッケージ、クレート、モジュールを利用して管理する - The Rust Programming Language 日本語版
- Cargoのワークスペース - The Rust Programming Language 日本語版
クレート(crate)
コンパイルは「クレート」が最小単位となっている。
バイナリクレートとライブラリクレートの種類が生まれるのはパッケージのようにも思うが、細かく区別する必要もないだろう。
バイナリクレートはcargo new --bin
(--bin
はデフォルトなのでなくてもよい)で作られるタイプでsrc/main.rs
がエントリーポイントと思っていて良いだろう。
ライブラリクレートはsrc/lib.rs
を持つ。
cargo add
はクレートを追加するManifestコマンドで、空のクレートを追加するのではなくCargo.toml
に依存関係を追加するコマンドである。
「Cargo.toml
Manifestファイル」と書いてあるので、ManifestコマンドはCargo.toml
に関するコマンドだろう。
パッケージ(package)
「パッケージ」は1つ以上のクレートを持つ。
cargo new
で作られるのはパッケージである。packageコマンドという分類になっている。
ライブラリクレートは最大でも1つなのでsrc/lib.rs
があるかどうかでわかる。
Cargo.toml
では[lib]
セクションでカスタマイズできる。
バイナリクレートもsrc/main.rs
があるかどうかでわかるのだが、こちらは複数持つことができる。その場合はsrc/bin/
にディレクトリを作ってmain.rs
を置く。
src/main.rs
を持たずにsrc/bin/*
に複数のディレクトリを作ってそれぞれにmain.rs
を持っても良い。
Cargo.toml
では[[bin]]
セクションでカスタマイズできる。括弧が1つ多い。
モジュール(module)
クレートやパッケージがどちらかといえば物理的?なのに対して、モジュールはどちらかといえば論理的なものだという印象を持った。
たぶんmod
で定義できるからそう感じるのだろう。
mod <mod名> {...}
という書き方はmod
の定義と宣言を兼ねている。
mod <mod名>;
とすると、このファイルでmod名
というモジュールを使用するという宣言になる。
mod
の定義
同じファイルの中にあるので定義と使用する宣言を兼ねている。
use
はC++のusing
とusing namespace
を混ぜたような使い方になる。
mod world_mod1 {
pub mod world_mod2 {
pub fn world_func() {
println!("abc world")
}
}
}
use world_mod1::world_mod2::world_func as w;
use world_mod1::world_mod2 as w2;
use world_mod1 as w3;
fn main() {
world_mod1::world_mod2::world_func();
w();
w2::world_func();
w3::world_mod2::world_func();
}
mod名
のファイルを作る
例えばhello_mod.rs
というファイルを作り、その中にhello_func()
という関数を作ったとする。
pub fn hello_func() {
println!("Hello, abc!");
}
それと同じディレクトリにあるmain.rs
からhello_func()
を呼び出したい場合はこうなる。
mod hello_mod;
fn main() {
hello_mod::hello_func();
}
つまりmod <ファイル名> {}
で定義したのと同じ意味を持つことになる。
ディレクトリを作ってその下にmod名
のファイルを作る
同じディレクトリではなく別のディレクトリにしたい場合もある。
hello_func()
を含んだファイルをhello_mod2.rs
とする。
ディレクトリhello_mod1
を作ってhello_mod2.rs
を移動させる。
そうすると、なんとなくmain.rs
からはmod hello_mod1::hello_mod2;
と書けばよさそうな気がするが、そうは書けない。
mod
に書けるのは単独のモジュール名だけで::
は使えないのだった。
その代わりに、hello_mod1.rs
というファイルをmain.rs
と同じディレクトリに作り、その中でpub mod hello_mod2;
と書く。
以前はmod.rs
というファイルに書く方式だったが今ではこうらしい。
モジュールツリー
モジュールは入れ子にできるので、モジュールツリーと呼ぶツリー構造として表すようになっている。
ツリーのルートはmain.rs
やlib.rs
である。
use world_mod1::world_mod2 as w2;
のように書いたあれは相対パスのような表現で、
これを絶対パスのような表現にするとuse crate::world_mod1::world_mod2 as w2;
とルートを表すcrate::
が頭に付く。
そうなると、モジュールとして扱えるのは今のクレートの中だけということになるのでは?
もちろんそういうことはなく、外部で既に公開されている関数などを使うこともできる。
「パッケージ」なのだ。
とはいえ実行ファイルを取り込むこともできないだろうから、ライブラリクレートを含むパッケージのはずである。
パッケージには最大で 1つまでしかライブラリクレートを持つことができないので、ライブラリクレートを持つパッケージのみuse
で使えるようにできるのだろう。
記載予定
- selfとかsuperとか