この記事で書くこと
rustのプロジェクトを管理する際に使われる概念について、学んだ内容をまとめました。以下のことがわかるように書きます。
- パッケージとは何か
- クレートとは何か
- モジュールとは何か
パッケージ、クレート、モジュールを使ったプロジェクト管理
パッケージ、クレート、モジュールの関係を図にしてみました。
パッケージは一つのディレクトリです。この中にはクレートと呼ばれるファイル(or ディレクトリ)が入っています。クレートには2種類あります。lib.rsがrootの「ライブラリクレート」とmain関数を含むファイル(上記の図ではbinと表記)がrootの「バイナリクレート」です。「ライブラリクレート」については、パッケージ内に1つまで(0でも良い)という制限があります。「バイナリクレート」はいくつでも良いです。各クレートは関連のある関数や構造体をひとまとまりとして、モジュールを作ることができます。これにより、小さく分割してプロジェクトを管理することができます。
パッケージの作り方
ライブラリクレートを含むパッケージを作成する場合
$ cargo new adder --lib
この場合、以下のようなパッケージができます。
$ tree adder
adder/
├── Cargo.toml
└── src
└── lib.rs
バイナリクレートを含むパッケージを作成する場合
cargo new add-one
この場合、以下のようなパッケージができます。
$ tree add-one/
add-one/
├── Cargo.toml
└── src
└── main.rs
ライブラリクレートとバイナリクレートを含むパッケージの作り方
両方のクレートを含むパッケージの構造は以下のようになります。
$ tree adder
adder/
├── Cargo.toml
└── src
├── lib.rs
└── main.rs
このような構造にするには、2通りの方法があります。といっても、cargoでパッケージを作って、手動で足りない方のファイルを追加するだけです。
$ cargo new adder --lib
$ touch adder/src/main.rs
$ cargo new adder
$ touch adder/src/lib.rs
ライブラリクレートと複数のバイナリクレートを含むパッケージの作り方
基本的には、「ライブラリクレートとバイナリクレートを含むパッケージの作り方」と同じですが、バイナリクレートを置く場所はbin以下になります。この中であれば、いくつでもバイナリクレートを置くことができます。
$ tree adder
adder/
├── Cargo.toml
└── src
├── bin
│ ├── hello.rs
│ └── hello_world.rs
└── lib.rs
モジュールへの分割
それぞれのクレートはモジュールへと分割することができます。上記の「ライブラリクレートと複数のバイナリクレートを含むパッケージ」のライブラリクレートをモジュールに分割してみます。
例えばadderのlib.rsが以下のようなライブラリクレートであったとします。
pub fn add_two(t: usize) -> usize {
t + 2
}
pub fn add_three(t: usize) -> usize {
t + 3
}
pub fn add(left: usize, right: usize) -> usize {
left + right
}
足し算を提供するクレートですが、「2つの引数を足す」関数と「ある数に定数を足す」関数で機能を分けることができます。ある数に定数を足す」関数をモジュールにしてみると以下のようになります。
mod add_something {
pub fn add_two(t: usize) -> usize {
t + 2
}
pub fn add_three(t: usize) -> usize {
t + 3
}
}
pub fn add(left: usize, right: usize) -> usize {
left + right
}
add_somethingモジュールを使いたいときは、useキーワードを使います。
mod add_something {
pub fn add_two(t: usize) -> usize {
t + 2
}
pub fn add_three(t: usize) -> usize {
t + 3
}
}
use add_something::*;
fn use_add_something(){
add_two(4);
add_three(4);
}
pub fn add(left: usize, right: usize) -> usize {
left + right
}
モジュールをファイルへ切り出す
モジュールは別ファイルへ書くことができます。上記の例を別ファイルに切り出すとき、以下の2通りの構成が可能です。
$ tree adder
adder/
├── Cargo.toml
└── src
├── add_something.rs
├── bin
│ ├── hello.rs
│ └── hello_world.rs
└── lib.rs
$ tree adder
adder/
├── Cargo.toml
└── src
├── add_something
│ └── mod.rs
├── bin
│ ├── hello.rs
│ └── hello_world.rs
└── lib.rs
このとき、lib.rsは以下のようになります。
mod add_something;
use add_something::*;
fn use_add_something(){
add_two(4);
add_three(4);
}
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
add_something.rsまたはadd_something/mod.rsは以下のようになります。
pub fn add_two(t: usize) -> usize {
t + 2
}
pub fn add_three(t: usize) -> usize {
t + 3
}
元々あった”mod add_something{}”の中身を別ファイルに移動して、”mod add_something;”にしました。rustではモジュールの構造はファイル配置の構造と一致するようになっています。
ここで使用した例について
ここで使用した例については、こちら(github)に上げています。どうぞご自由にお使いください。
コメント