blog.dopana

Back

Rustのプロジェクトが単一ファイルを超えて成長するにつれて、コードの整理とスコープ管理が極めて重要になります。Rustはカプセル化、プライバシー、再利用性を両立する強力なモジュールシステムを提供しています。

10歳でもわかる説明:おもちゃ工場と各部門#

大きなおもちゃ工場を建てる場面をイメージしてください:

  1. Package (Cargo.toml): 工場敷地全体であり、設計図、納品伝票、工具一式を含んでいます。
  2. Crate (クレート): クライアントやお客さんにそのまま出荷できる完成品の輸送コンテナ(実行可能バイナリまたはライブラリ)。
  3. Module (モジュール): 工場内の個別の部屋・作業部門(例:木工部門、塗装部門、品質管理室)。
  4. 公開範囲 (pub): 鍵のかかった作業ドア(private)と、来客用の受付窓口(pub)。Rustでは安全のため、初期状態ですべてのドアに鍵がかかっています。
graph TD
    subgraph Package ["Package (Cargo.toml)"]
        subgraph BinaryCrate ["Binary Crate (src/main.rs)"]
            MainFn["main() entry point"]
        end
        subgraph LibraryCrate ["Library Crate (src/lib.rs)"]
            RootMod["Crate Root (crate::)"]
            RootMod --> ModFront["mod front_of_house"]
            ModFront --> ModHosting["pub mod hosting"]
            ModHosting --> FnAdd["pub fn add_to_waitlist()"]
            RootMod --> ModBack["mod back_of_house"]
            ModBack --> FnCook["fn fix_incorrect_order()"]
        end
    end
    MainFn -->|use restaurant::front_of_house::hosting| FnAdd

階層構造の定義#

単位定義ファイル配置ルール
Package1つ以上のCrateのビルド方法を記述した Cargo.toml を含む Cargo の機能単位。Cargo.toml が置かれたルートディレクトリ
Crateライブラリまたは実行可能バイナリを生成するモジュールツリー。src/main.rs (バイナリ) または src/lib.rs (ライブラリ)
Moduleコードをグループ化し、内部要素の公開・非公開を制御する単位。インライン mod name { ... } または src/name.rs
Pathモジュールツリー内の要素(構造体・関数など)を指定するパス。crate::front_of_house::hosting::add_to_waitlist()

モジュールとプライバシールール#

Rustにおいて、すべての要素(関数、メソッド、構造体、列挙型、モジュール)はデフォルトで親モジュールに対して非公開(private)です。

graph LR
    Parent["親モジュール"] -->|子モジュールのすべてを参照可能| Child["子モジュール"]
    Child -->|非公開の兄弟要素は参照不可| Sibling["兄弟要素"]
    Child -->|親モジュールの要素は常に参照可能| Parent

レストラン業務の例#

[!NOTE] モジュールを pub mod にしても、公開されるのはモジュール自体へのアクセスのみです。内部の関数やフィールドは個別に pub を付与しない限り非公開のままです。

構造体と列挙型における pub の違い#

構造体と列挙型では、公開範囲の扱いが異なります:

  • 構造体 (Struct): pub struct を指定しても名前が公開されるだけで、各フィールドは個別に pub を付けない限り非公開のままです。
  • 列挙型 (Enum): pub enum を指定すると、含まれるすべてのヴァリアント(列挙子)が自動的に公開されます。

use によるスコープ導入#

長いパスを何度も記述するのを防ぐため、use キーワードを使ってローカルスコープにシンボリックリンクのように要素を導入します:

sequenceDiagram
    participant Code as 呼び出し側コード
    participant Scope as ローカルスコープ
    participant CrateTree as クレートモジュールツリー

    Note over Scope,CrateTree: use crate::front_of_house::hosting;
    Scope->>CrateTree: hosting モジュールのパスを解決
    CrateTree-->>Scope: 現在のスコープに別名 hosting を定義
    Code->>Scope: hosting::add_to_waitlist()
    Scope->>CrateTree: front_of_house::hosting::add_to_waitlist() を実行

pub use による再エクスポート#

use でスコープに導入した要素は現在のスコープ内で非公開です。pub use を使うことで外部の利用者に対しても公開でき、整った公開APIを設計できます:

src/lib.rs
mod front_of_house {
    pub mod hosting {
        pub fn add_to_waitlist() {}
    }
}

// 再エクスポート: 外部から restaurant::hosting::add_to_waitlist() で直接利用可能
pub use crate::front_of_house::hosting;
rust

モジュールを複数ファイルに分割する#

プロジェクトが大きくなったら、ファイルシステムに対応させて分割管理します:

my_project/
├── Cargo.toml
└── src/
    ├── main.rs
    ├── lib.rs
    └── front_of_house/
        ├── mod.rs (または front_of_house.rs)
        └── hosting.rs
text
src/lib.rs
// front_of_house モジュールを宣言(Rustが src/front_of_house.rs を読み込み)
pub mod front_of_house;

pub use crate::front_of_house::hosting;
rust
src/front_of_house.rs
// hosting サブモジュールを宣言(Rustが src/front_of_house/hosting.rs を読み込み)
pub mod hosting;
rust
src/front_of_house/hosting.rs
pub fn add_to_waitlist() {
    println!("ウェイティングリストに追加しました!");
}
rust

まとめ#

  • Package は Cargo.toml で管理される1つ以上のCrateの集合体。
  • Crate はバイナリまたはライブラリを出力するコンパイル単位。
  • Module (mod) はコードを階層的に整理し、アクセススコープを制御。
  • すべての要素はデフォルトで非公開であり、pub で明示的に公開。
  • use による簡潔なスコープ導入と pub use による洗練されたAPI再エクスポートを活用。

参考資料#