Chapter 24

モジュール

mebiusbox
mebiusbox
2023.05.06に更新

📌 モジュールを定義

モジュールの定義は mod を使います.モジュールの本体は {} で囲みます.モジュールの中にモジュールを定義できます.

mod M1 {
    mod M2 {
        mod M3 {
            fn hoge() {}
        }
    }
    
    mod M4 {
        fn foo() {}
        fn bar() {}
    }
}

モジュールは同じモジュール内に対してだけ公開された状態になります.そこで,外部のモジュールに対しても公開するには pub を使います. pub はモジュール,関数,構造体などに1つずつ設定できます.

pub mod M1 {
    pub mod M2 {
        pub mod M3 {
            pub fn hoge() {}
        }
    }
}

📌 パス

モジュールを利用するには パス が必要です.モジュールの起点はクレートルートで,パスは crate になります.前のコードが src/main.rs に含まれていた場合,それぞれのパスは次のようになります.

crate
└─ M1
    ├─ M2
    │   └─ M3
    │       └── hoge
    └─ M4
        ├── foo
        └── bar

パスの指定には2種類あります.絶対パスと相対パスです.絶対パスはクレートルートを表す crate,または外部パッケージおよび標準ライブラリの場合はパッケージ名から指定できます.相対パスの場合は self, または super を使います. self は現在のモジュールから, super は親のモジュールからの指定になります.パスの区切りは :: を使います.ちなみに self:: は省略できます.

crate::M1::M2::M3::hoge

📌 モジュールの利用

モジュールを利用するには use を使ってパスを指定します:

use crate::M1::M2::M3::hoge;
use std::fmt::Result;

use で指定したパスに as で別名をつけられます:

use std::io::Result as IoResult;

use で指定するパスにおいて,あるモジュールから別々のパスを指定する場合,それぞれのパスを use で指定すると必要な行が増えてしまいます.そこで,パスのリストを記述できます:

use crate::M1::{M2::M3, M4};

また,あるモジュール以下をすべて現在のスコープで利用する場合はグロブ(*)を指定できます:

use crate::M1::*;

📌 モジュールツリー

クレートそのものがモジュールであり,クレートルートは src/main.rs ファイルで,パスは crate でした.Rust のモジュールシステムはクレートルート以下のフォルダとファイルもまたモジュールと見なします.これによって別々のファイルに実装を分けられます.

mod では {} で囲む他に,指定した名前と同じファイルを同じフォルダ内から検索して,その中身を挿入できます.例えば, src/hoge.rs というファイルがあるとします. src/main.rs から mod hoge; とすれば src/hoge.rs の中身を src/main.rs ファイルに挿入します.ここで src/hoge.rs の中身が次のようになっているとします.

pub fn hoge() {}

この場合, src/main.rs からは crate::hoge::hoge() で呼び出せます.このフォルダとファイルによるモジュールの作り方が2種類あります.

🔹 Rust2015方式

下図のようなフォルダ構成を考えます.このような構成にすると, src/main.rs から mod module1; とすることで, src/module1/mod.rs ファイルが読み込まれます.そのファイルの中身は pub mod foo; とします.これで,src/main.rs から src/module1/foo.rs のモジュールを利用できます.同じように pub mod bar;mod.rs に追加すれば bar.rs モジュールも利用できるようになります.このようにモジュールの階層を作ってプログラムを構築できます.これを モジュールツリー といいます.

(workspace)
├─ src
│   ├── main.rs
│   └─ module1
│       ├── mod.rs
│       ├── foo.rs
│       └── bar.rs
├── cargo.toml
└── .gitignore

rust-moduletree01

🔹 Rust2018方式

もう1つのモジュールツリーの作り方ですが,下図を見てください.今度は mod.rs ファイルの代わりに,フォルダと同じファイル module1.rs が存在しています.このファイルの中身は mod.rs と同じになります.ファイルの構成が違いますが,モジュールツリーは同じなので,コードに変更はありません.

(workspace)
├─ src
│   ├── main.rs
│   ├── module1.rs
│   └─ module1
│       ├── foo.rs
│       └── bar.rs
├── cargo.toml
└── .gitignore

rust-moduletree02

Rust2015方式ではmod.rsファイルが多く作られる問題があります.Rust2018方式ではモジュールのフォルダと同じ名前のファイルを作成することでこの問題を避けることができます.Rust2015方式はとくに非推奨となっているわけではないですし、現時点では好きな方を使えばいいと思います.

📌 モジュールの再公開

pub use を使うことで,外部モジュールからでも,指定したパスで利用できるようになります.これを再公開といいます.

pub use crate::module1;