LoginSignup
153
118

More than 5 years have passed since last update.

Rust のモジュールシステム

Last updated at Posted at 2015-06-27

クレート

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
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 をつくる。

src/foo.rs
pub fn hello() {
  println!("Hello, World!!");
}

pub mod bar {
  pub fn hello() {
    println!("Hello, World!!!");
  }
}
src/main.rs
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
src/foo/mod.rs
pub fn hello() {
  println!("Hello, World!!");
}

pub mod bar; // さらに内部のモジュール bar を公開
src/foo/bar.rs
pub fn hello() {
  println!("Hello, World!!!");
}

bar.rs は、mod bar; を記述してある src/foo/mod.rs とおなじディレクトリに置く。

src/main.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

src/foo/bar/mod.rs
pub fn hello() {
  println!("Hello, World!!!");
}

と記述してもいい。もちろんファイルをわけないで、src/foo/mod.rs

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
src/foo/bar/mod.rs
fn hello() {
  println!("Hello, World!!!");
}
src/foo/mod.rs
fn hello() {
  println!("Hello, World!!");
}

pub mod bar;
src/lib.rs
pub mod foo;
src/main.rs
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!!!

ポイント

この例だとひとつのクレートにモジュール用と実行形式用が同居している。

useuse some_crate::{some_module1, some_module2}; のように同時に複数指定もできる。

src/foo/mod.rs

src/foo/mod.rs
pub fn hello() {
  println("Hello, World!!");
}

pub use self::bar::hello as greet; // 別名で公開 (mod bar; の先に記述する)

mod bar; // 内部は非公開にしたいので pub を取り除いた

とすると、mainfoo::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
src/Cargo.toml
[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 がつかわれる。

src/main.rs
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 にする必要もない。

153
118
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
153
118