モジュールを定義して、スコープとプライバシーを制御する

この節では、モジュールと、その他のモジュールシステムの要素 ――すなわち、要素に名前をつけるための パス 、パスをスコープに持ち込むuseキーワード、要素を公開するpubキーワード―― について学びます。 また、asキーワード、外部パッケージ、glob演算子についても話します。 とりあえず、今はモジュールに集中しましょう!

モジュール はクレート内のコードをグループ化し、可読性と再利用性を上げるのに役に立ちます。 モジュールは要素の プライバシー も制御できます。プライバシーとは、要素がコードの外側で使える (公開 public) のか、内部の実装の詳細であり外部では使えない (非公開 private) のかです。

例えば、レストランの機能を提供するライブラリクレートを書いてみましょう。 実際にレストランを実装することではなく、コードの関係性に注目したいので、関数にシグネチャをつけますが中身は空白のままにします。

レストラン業界では、レストランの一部を 接客部門 (front of house) といい、その他を 後方部門 (back of house) といいます。 接客部門とはお客さんがいるところです。接客係がお客様を席に案内し、給仕係が注文と支払いを受け付け、バーテンダーが飲み物を作ります。 後方部門とはシェフや料理人がキッチンで働き、皿洗い係が食器を片付け、マネージャが管理業務をする場所です。

私達のクレートを現実のレストランと同じような構造にするために、関数をネストしたモジュールにまとめましょう。 restaurantという名前の新しいライブラリをcargo new --lib restaurantと実行することで作成し、Listing 7-1 のコードを src/lib.rs に書き込み、モジュールと関数のシグネチャを定義してください。

ファイル名: src/lib.rs

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

fn main() {}

Listing 7-1: front_of_houseモジュールにその他のモジュールが含まれ、さらにそれらが関数を含んでいる

モジュールは、modキーワードを書き、次にモジュールの名前(今回の場合、front_of_house)を指定することで定義されます。 モジュールの中には、今回だとhostingservingのように、他のモジュールをおくこともできます。 モジュールにはその他の要素の定義も置くことができます。例えば、構造体、enum、定数、トレイト、そして(Listing 7-1のように)関数です。

モジュールを使うことで、関連する定義を一つにまとめ、関連する理由を名前で示せます。 このコードを使うプログラマーは、定義を全部読むことなく、グループ単位でコードを読み進められるので、欲しい定義を見つけ出すのが簡単になるでしょう。 このコードに新しい機能を付け加えるプログラマーは、プログラムのまとまりを保つために、どこにその機能のコードを置けば良いのかがわかるでしょう。

以前、 src/main.rssrc/lib.rs はクレートルートと呼ばれていると言いました。 この名前のわけは、 モジュールツリー と呼ばれるクレートのモジュール構造の根っこ (ルート)にこれら2つのファイルの中身がcrateというモジュールを形成するからです。

Listing 7-2は、Listing 7-1の構造のモジュールツリーを示しています。

crate
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

Listing 7-2: Listing 7-1 のコードのモジュールツリー

このツリーを見ると、どのモジュールがどのモジュールの中にネストしているのかがわかります(例えば、hostingfront_of_houseの中にネストしています)。 また、いくつかのモジュールはお互いに 兄弟 の関係にある、つまり、同じモジュール内で定義されていることもわかります(例えばhostingservingfront_of_houseで定義されています)。 他にも、家族関係の比喩を使って、モジュールAがモジュールBの中に入っている時、AはBの であるといい、BはAの であるといいます。 モジュールツリー全体が、暗黙のうちに作られたcrateというモジュールの下にあることにも注目してください。

モジュールツリーを見ていると、コンピュータのファイルシステムのディレクトリツリーを思い出すかもしれません。その喩えはとても適切です! ファイルシステムのディレクトリのように、モジュールはコードをまとめるのに使われるのです。 そしてディレクトリからファイルを見つけるように、目的のモジュールを見つけ出す方法が必要になります。