パッケージとクレート

最初に学ぶモジュールシステムの要素は、パッケージとクレートです。 クレートはバイナリかライブラリのどちらかです。 クレートルート (crate root) とは、Rustコンパイラの開始点となり、クレートのルートモジュールを作るソースファイルのことです(モジュールについて詳しくは「モジュールを定義して、スコープとプライバシーを制御する」のセクションで説明します)。 パッケージ はある機能群を提供する1つ以上のクレートです。 パッケージは Cargo.toml という、それらのクレートをどのようにビルドするかを説明するファイルを持っています。

パッケージが何を持ってよいかはいくつかのルールで決まっています。 パッケージは0個か1個のライブラリクレートを持っていないといけません。それ以上は駄目です。 バイナリクレートはいくらでも持って良いですが、少なくとも(ライブラリでもバイナリでも良いですが)1つのクレートを持っていないといけません。

パッケージを作る時に何が起こるか見てみましょう。 まず、cargo newというコマンドを入力します:

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

このコマンドを入力したとき、Cargoは Cargo.toml ファイルを作り、パッケージを作ってくれました。 Cargo.toml の中身を見ても、src/main.rs については何も書いてありません。これは、Cargoは src/main.rs が、パッケージと同じ名前を持つバイナリクレートのクレートルートであるという慣習に従っているためです。 同じように、Cargoはパッケージディレクトリに src/lib.rs が含まれていたら、パッケージにはパッケージと同じ名前のライブラリクレートが含まれており、src/lib.rs がそのクレートルートなのだと判断します。 Cargoはクレートルートファイルを rustcに渡し、ライブラリやバイナリをビルドします。

今、このパッケージには src/main.rs しか含まれておらず、つまりこのパッケージはmy-projectという名前のバイナリクレートのみを持っているということです。 もしパッケージが src/main.rssrc/lib.rs を持っていたら、クレートは2つになります:どちらもパッケージと同じ名前を持つ、ライブラリクレートとバイナリクレートです。 ファイルを src/bin ディレクトリに置くことで、パッケージは複数のバイナリクレートを持つことができます。それぞれのファイルが別々のバイナリクレートになります。

クレートは、関連した機能を一つのスコープにまとめることで、その機能が複数のプロジェクト間で共有しやすいようにします。 例えば、2章で使ったrandクレートは、乱数を生成する機能を提供します。 randクレートを私達のプロジェクトのスコープに持ち込むことで、この機能を私達のプロジェクトで使うことができます。 randクレートが提供する機能にはすべて、クレートの名前randを使ってアクセスできます。

クレートの機能をそれ自身のスコープの中に入れたままにしておくことは、ある機能が私達のクレートで定義されたのかrandクレートで定義されたのかを明確にし、名前の衝突を予防してくれます。 例えば、randクレートはRngという名前のトレイトを提供しています。 更に、私達のクレートでRngという名前のstructを定義することもできます。 クレートの機能はそのスコープ内の名前空間に位置づけられているので、randを依存先として追加しても、コンパイラはRngという名前が何を意味するのかについて混乱することはないのです。 私達のクレートでは、私達の定義したstruct Rngのことであり、randクレートのRngトレイトにはrand::Rngでアクセスするというわけです。

では、モジュールシステムの話に移りましょう!