クレート
Rust
では crate
(木箱) という単位でプログラムを開発する。cargo new
で生成される単位が crate
だ。
foo
という実行ファイルをつくるには、
cargo new foo --bin
として crate
を生成し、bar
というライブラリをつくるには、
cargo new bar
とする。
モジュール
ひとつのファイルに書く
ひとつのファイルの中にモジュールを作成できる。
$ cargo new mod_example1 --bin
$ tree
| Cargo.toml
|
\---src
main.rs
fn hello() {
println!("Hello, World!");
}
// モジュール
mod foo {
// 外から使うので pub をつける
pub fn hello() {
println!("Hello, World!!");
}
// モジュールは入れ子にできる
// やっぱり外から使うので pub をつける
pub mod bar {
pub fn hello() {
println!("Hello, World!!!");
}
}
}
fn main() {
hello();
foo::hello();
foo::bar::hello();
}
$ cd mod_example1
$ cargo run
Hello, World!
Hello, World!!
Hello, World!!!
ファイルをわける
いつまでもひとつのファイルに書き続けられない。
$ cargo new mod_example2 --bin
$ tree
| Cargo.toml
|
\---src
foo.rs
main.rs
main.rs
(使う側) とおなじ階層に、モジュール名をファイル名とした foo.rs
をつくる。
pub fn hello() {
println!("Hello, World!!");
}
pub mod bar {
pub fn hello() {
println!("Hello, World!!!");
}
}
fn hello() {
println!("Hello, World!");
}
mod foo; // モジュールの読み込み
fn main() {
hello();
foo::hello();
foo::bar::hello();
}
$ cd mod_example2
$ cargo run
Hello, World!
Hello, World!!
Hello, World!!!
ディレクトリをわける
おなじディレクトリにファイルがたくさんあるのはいやだ。整理したい。
$ cargo new mod_example3 --bin
$ tree
| Cargo.toml
|
\---src
| main.rs
|
\---foo
bar.rs
mod.rs
pub fn hello() {
println!("Hello, World!!");
}
pub mod bar; // さらに内部のモジュール bar を公開
pub fn hello() {
println!("Hello, World!!!");
}
bar.rs
は、mod bar;
を記述してある src/foo/mod.rs
とおなじディレクトリに置く。
fn hello() {
println!("Hello, World!");
}
mod foo; // foo/mod.rs を参照
fn main() {
hello();
foo::hello();
foo::bar::hello();
}
$ cd mod_example3
$ cargo run
Hello, World!
Hello, World!!
Hello, World!!!
ポイント
mod bar;
と記述すると ./bar.rs
か ./bar/mod.rs
が参照される。両方あるときはエラーになる。
この例だと src/foo/bar.rs
の代わりに src/foo/bar/mod.rs
に
pub fn hello() {
println!("Hello, World!!!");
}
と記述してもいい。もちろんファイルをわけないで、src/foo/mod.rs
に
pub fn hello() {
println!("Hello, World!!");
}
pub mod bar {
pub fn hello() {
println!("Hello, World!!!");
}
}
としてもいい。mod foo;
のところも同じだ。
クレートをわける
使う側と使われる側は別に扱いたい。
$ cargo new mod_example4 --bin
$ tree
| Cargo.toml
|
\---src
| lib.rs
| main.rs
|
\---foo
| mod.rs
|
\---bar
mod.rs
fn hello() {
println!("Hello, World!!!");
}
fn hello() {
println!("Hello, World!!");
}
pub mod bar;
pub mod foo;
extern crate mod_example4; // 外部のクレートを読み込む (この場合は lib.rs)
use mod_example4::foo; // プリフィックスのクレート名を省略できるようにする
fn hello() {
println!("Hello, World!");
}
fn main() {
hello();
foo::hello(); // foo:: でアクセスできる
foo::bar::hello();
}
use
しないと mod_example4::foo::hello()
などと書かないといけない。
$ cd mod_example4
$ cargo run
Hello, World!
Hello, World!!
Hello, World!!!
ポイント
この例だとひとつのクレートにモジュール用と実行形式用が同居している。
use
は use some_crate::{some_module1, some_module2};
のように同時に複数指定もできる。
src/foo/mod.rs
を
pub fn hello() {
println("Hello, World!!");
}
pub use self::bar::hello as greet; // 別名で公開 (mod bar; の先に記述する)
mod bar; // 内部は非公開にしたいので pub を取り除いた
とすると、main
で foo::great()
を呼び出すと、内部的に foo::bar::hello()
が呼び出されるようになる。実装内部を隠蔽してインタフェースだけを公開するのに便利だ。self
を指定しているのはこのモジュールからの相対位置をあらわすためで、たんに bar::hallo
とするとトップレベルからのパスで探索される。また、ひとつ上のモジュールを指定するには super
を指定する。
GitHub をつかう
これはモジュール用と実行形式用を完全にわける例。
モジュール側
$ cargo new happy
$ tree
| Cargo.toml
|
\---src
| lib.rs
|
\---foo
| mod.rs
|
\---bar
mod.rs
ソースコードの内容はクレートをわける例とおなじ。
できたら GitHub に登録しておく。
利用側
$ cargo new mod_example5 --bin
$ tree
| Cargo.toml
|
\---src
main.rs
[package]
name = "mod_example5"
version = "0.1.0"
authors = ["Shinya Kitaoka <skitaoka@gmail.com>"]
[dependencies.happy]
git = "https://github.com/skitaoka/happy.git"
rev = "cd8c9ad6d035e8cdf99a0ffffe0e0e565d257143"
リビジョン指定がないと HEAD がつかわれる。
extern crate happy;
use happy::foo;
fn hello() {
println!("Hello, World!");
}
fn main() {
hello();
foo::hello();
foo::bar::hello();
}
$ cd mod_example5
$ cargo run
Hello, World!
Hello, World!!
Hello, World!!!
git submodule
にする必要もない。