Rust独学メモ
PackageとCrate
最初にRust入門した時には、cargo newして、コードを実装して、テストを書いて、何となく動いたわーい、って誰しもやると思う。でもある程度構造化されたプログラムを組もうとすると
ユーザ定義型・メソッド・関数 < モジュール階層 < クレート < パッケージ
という風に階層的に管理する必要が出てくる。モジュールの階層は、ディレクトリ構造に対応しているので分かりやすいが、クレートとパッケージはどのような関係にあるのだろう。また最初に cargo new して作るものが一体何なのか、少しわかりにくいのではないだろうか。The Bookによると
A crate is the smallest amount of code that the Rust compiler considers at a time.
クレートとはRustコンパイラが一度に考慮するコードの最小単位である ⇒ コンパイル単位であるということか。ライブラリ全体がコンパイル単位なので、forward declaration のようなことをしなくてよいのだろうと推測
A crate can come in one of two forms: a binary crate or a library crate.
クレートにはバイナリと、ライブラリ・クレートの2種類 ⇒ OK
でもって、バイナリには main 関数がある。まあいいでしょう。
The crate root is a source file that the Rust compiler starts from and makes up the root module of your crate
クレート・ルート、はソースファイルで、ルート・モジュールを構成する起点となる。(なんか新しい概念が2つ提示された。詳しくは後で、だと)
A package is a bundle of one or more crates(中略)A package contains a Cargo.toml file that describes how to build those crates.
パッケージは1つ以上のクレートを束ねたもの ⇒ OK。最初に提示した図の通り
パッケージは Cargo.toml ファイルを含む ⇒ なるほど、Cargo.toml を見たら、そこにパッケージがあると思えばよい
さらに、続いて
A package can contain as many binary crates as you like, but at most only one library crate.
パッケージ内には好きな数だけバイナリクレートを作ることができる。でもライブラリクレートは最大1個 ⇒ バンドルと言いつつライブラリは1つですか…。恣意的かつ大胆なデザイン
cargo new してできたフォルダには Cargo.toml があるので、cargo new で作られたものは、まごうことなくパッケージであると理解できた。それでは、クレートはどこにあるのだろうか?
src/main.rs is the crate root of a binary crate with the same name as the package. Likewise, Cargo knows that if the package directory contains src/lib.rs
src/main.rs が、パッケージと同名のバイナリクレートのクレート・ルート。src/lib.rs がパッケージと同名のライブラリクレートのクレート・ルート ⇒ このファイルの存在が、クレートの定義と同義。パッケージと同名のバイナリクレートを作りたかったら src/main.rs を置けば良くて、ライブラリクレートを作りたかったら、src/lib.rs を置くしかない(パッケージに作れるライブラリクレートは最大1個までだから)ということ。ライブラリを作成するにあたっては、パッケージとクレートは一対一対応している。
ところで、先ほど「パッケージ内には好きな数だけバイナリクレートを作ることができる」とあった、それを実現するにはどうすればよいのだろう?
A package can have multiple binary crates by placing files in the src/bin directory: each file will be a separate binary crate.
src/bin ディレクトリを作ってその下に、ファイルを作ればよい。それぞれのファイルが別々のバイナリクレートになる ⇒ さっき src/main.rs はクレート・ルートだと説明を受けたが、src/bin 以下のファイルはクレートになる。それはクレート・ルート?説明一貫してなくないか?
まとめ
- cargo new では、パッケージと、パッケージと同名のクレートのクレート・ルートが作成される
- ライブラリクレートを作りたかったら、クレート・ルートとなる src/lib.rs ファイルを置く
- パッケージと同名のバイナリクレートを作りたかったら、クレート・ルートとなる src/main.rs ファイルを置いて main 関数を書く
- それ以外のバイナリクレートを作りたかったら src/bin フォルダを置いて、任意の .rs ファイルを置くと、そのファイルひとつひとつが、バイナリクレートのクレート・ルートになる
ここが残念
- クレートとは、プログラムの構造上は、プログラムの階層構造の中では、モジュールの上に来る名前空間であるのと同時に、Rustのコンパイル単位のことでもある。
- crates.io で検索して cargo add で依存関係を付けているのはパッケージ(に一対一対応したクレート)。パッケージのことをクレートと呼んで、クレートはRustコンパイラの実装の中に留めていたほうが良かったのではないか
- Cargo.toml には [workspace] という概念があって、パッケージの中にパッケージが作れる。「パッケージにライブラリクレートは最大1個」しか作れないが、パッケージは作れる。こんな詭弁が許されるのは、愛されているが故なのか。ここはもう少し掘り下げて調べてみることにする予定
- モジュール化の根幹にある crate がコンパイル単位であり、ライブラリのことであり、実行ファイルでもあり、パッケージも含意している多義的で曖昧な用語になっている。語彙が乏しい人が作った残念なライブラリ臭がする。美しい世界ではない
- 「クレートはコンパイル単位であり、パッケージはクレートのメタ情報を定義する場所」であることは、少なくとも言えそう。それ以外の説明は The Book を持ってしても的確では無いように思えてならない