モジュールを追加する
モジュール (Rustリファレンス) はRustのコードの単位で、カプセル化とプライバシー制御の境界にもなります。本セクションではモジュールの種類と、各種類のモジュールを追加する方法について解説します。
ルートモジュール
最初に意識しておきたいのが、Rustプロジェクトを追加して最初に現れる src/lib.rs
ファイルがルートモジュールであるという点です。
ルートモジュールのパスは常に crate
です。以下の例で示されているように、このモジュールで定義されている項目は crate::greet
のようにして参照します。(root_task
は Rustタスクを追加する で追加した関数です。)
// core ------ ...
// std ------- ...
// crate --+-- root_task
// |
// '-- greet
#[no_mangle]
extern "C" fn root_task(_: usize) {
// 現在モジュールのパスは `crate` なので、以下の2行は同等
greet();
crate::greet();
}
fn greet() {
println!("Hello!");
}
モジュールツリーはルートモジュールと外部クレート (標準ライブラリクレートおよび他に追加したライブラリクレート) を根とした階層構造で構成されます。モジュールの中に mod
項目を記述することで子モジュールを宣言していきます。子モジュールの定義方法に応じてインラインモジュールと非インラインモジュールがあります。
インラインモジュール
mod
項目に続けて定義を記述するタイプのモジュールをインラインモジュールと呼びます。前の例の greet
関数を mod greeter { ... }
で囲ってみましょう。
// core ------ ...
// std ------- ...
// crate --+-- root_task
// |
// '-- greeter -- greet
#[no_mangle]
extern "C" fn root_task(_: usize) {
// 現在モジュールのパスは `crate` なので、以下の2行は同等
greeter::greet();
crate::greeter::greet();
}
mod greeter { // <-----
pub(crate) fn greet() {
println!("Hello!");
}
} // <-----
この場合、 greet
関数の完全パスは crate::greeter::greet
になります。デフォルトではモジュール内で定義された項目は外からはアクセスできません。ここでは pub(crate)
(Rustリファレンス) を指定することで、 crate
とその子孫モジュールからアクセスできるようにしています。
非インラインモジュール
もっと一般的なモジュールの定義方法は、外部のソースファイルで定義する方法です。このタイプのモジュールを非インラインモジュールと呼びます。
非インラインモジュールのソースファイルのパスは2種類の方式があります。
mod-rs方式: ルートモジュール (
src/lib.rs
, etc.) および名前/mod.rs
のようなパスのソースファイルがこれに該当します。子モジュールは同じディレクトリで定義します (e.g.,名前/子.rs
)。non-mod-rs方式:
mod.rs
以外の名前のソースファイル (e.g.,名前.rs
) がこれに該当します。子モジュールは兄弟ディレクトリ内で定義します (e.g.,名前/子.rs
)。子モジュールがなければこのディレクトリは不要です。
Note
ルートモジュール以外に関してはnon-mod-rs方式を採用することが推奨されています。理由の一つとして、mod-rs方式ではテキストエディタやIDE上で mod.rs
という表題のタブが並んでしまうことが挙げられます。
前のコード例のインラインモジュールをIDE上でnon-mod-rs方式の非インラインモジュールに変換するには、次の手順を踏みます。
ルートモジュール
src/lib.rs
はmod-rs方式なので、その子モジュールはsrc
内に作成します。 ソリューション エクスプローラー でsrc
を右クリックし、 [追加]-[新しい項目...] から .rs を選択し、名前を設定後、 追加(A) をクリックします。Note
基本的にはファイル名がそのままモジュール名になります。この場合、
greeter.rs
という名前にしてください。
親モジュール内 (
src/lib.rs
,crate
) で、この子モジュールを宣言します。これはセミコロンで終わる形 (mod greeter;
) でmod
項目を記述することで行います。#[no_mangle] extern "C" fn root_task(_: usize) { // 現在モジュールのパスは `crate` なので、以下の2行は同等 greeter::greet(); crate::greeter::greet(); } mod greeter; // <-----
注意
単にソースファイルを追加するだけではモジュールツリーには追加されず、コンパイル対象になりません。上記のように必ず mod
項目を追加するようにしてください。
子モジュール (
src/greeter.rs
,crate::greeter
) の内容を定義します。pub(crate) fn greet() { println!("Hello!"); }
孫モジュール
上に続けて、さらに crate::greeter
の子モジュール crate::greeter::inner
(crate
からの視点では孫モジュール) も作成する手順を見てみましょう。この子モジュールも同じくnon-mod-rs方式で作成します。
親モジュール (
src/greeter.rs
,crate::greeter
) 内で子モジュールを宣言します。mod inner; // <----- pub(crate) fn greet() { println!("Hello!"); }
src/greeter.rs
はnon-mod-rs方式なので、子モジュールはsrc/greeter/
内に作成します。 ソリューション エクスプローラー でsrc
を右クリックし、 [追加]-[新しいフォルダー] を選択し、greeter
という名前のサブディレクトリを作成します。
作成したディレクトリ内に子モジュールのソースファイル
inner.rs
を作成します。このソースファイルがcrate::greeter::inner
となります。
さらに詳しく
The Rust Reference, "The path attribute" (非インラインモジュールのソースファイルパスをオーバライドする方法)
The Rust Programming Language, "Paths for Referring to an Item in the Module Tree" (絶対・相対パスの記法)
The Rust Programming Language, "Bringing Paths into Scope with the use Keyword" (別モジュールの項目を
use
キーワードを使用してスコープに持ってくる方法)