【Rust】モジュールとファイル分割

## はじめに

Rustにはモジュールというスコープに名前を付ける機能があります。
自分はこのモジュールについて理解せずにファイルを分割してエラーで苦労しました。

## 同じファイル内でのモジュール

`mod モジュール名 {}`でモジュールを定義できます。
モジュール内の要素はデフォルトでは非公開です。
外部に公開する場合は`pub`を付ける必要があります。

モジュール内の要素へアクセスする際は`::`を使います。

```rust:src/main.rs
mod module1 {
    pub fn func1() -> String {
        "ABC".to_string()
    }

    fn func2() -> String {
        "DEF".to_string()
    }
}

fn main() {
    println!("{}", crate::module1::func1());
    println!("{}", module1::func1());
}
```

`main`関数から`func1`関数を呼び出す場合は以下の様な記述方法があります。
* `crate::module1::func1` (絶対パス)
* `module1::func1` (相対パス)


`func2`は`pub`が付いてないので`main`関数からアクセスすることはできません。

### モジュールの階層構造

モジュールは`crate`をルートとする階層構造になっています。
上の`main.rs`のモジュールの構造を表すと以下の様になります。

```:モジュールの階層構造
crate
 ┣━ module1
 ┃   ┣━ func1
 ┃   ┗━ func2
 ┗━ main
```


### `use`キーワード

`use`キーワードを使うとパスを省略して呼び出すことができます。

```rust:src/main.rs
mod module1 {
    pub fn func1() -> String {
        "ABC".to_string()
    }
}

use module1::func1; // func1関数を直接呼び出せるようになる

fn main() {
    println!("{}", func1());
}
```

## ファイルを分割した場合のモジュール

### パターン1

ファイル分割をするとファイル名がそのままモジュール名になります。
例として、以下の様にファイルを分割します。

```
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┗━ module1.rs
```

`module1.rs`には以下の様な関数があります。
この`func`関数は`module1`モジュール内にあると認識されます。

```rust:src/module1.rs
pub fn func() -> String {
    "ABC".to_string()
}
```

またファイルを分割した場合、**必ず**`main.rs`内でモジュールを宣言する必要があります。
宣言がないとモジュールが見つからずエラーになります。

```rust:src/main.rs
mod module1; // この宣言が必要

fn main() {
    println!("{}", module1::func());
}
```

モジュールの階層構造は以下の様になります。
ファイル名がモジュール名になると説明しましたが`main.rs`は例外となります。
そのため、`crate`の直下に`main`関数があります。

```:モジュールの階層構造
crate
 ┣━ main # これはmain関数
 ┗━ module1
     ┗━ func
```

### パターン2

次に以下の様なファイル構成の場合を考えます。

```
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┣━ module1.rs
    ┗━ module2.rs
```

```rust:src/main.rs
mod module1;
mod module2;

fn main() {
    println!("{}", module1::func());
    println!("{}", module2::func());
}
```

```rust:src/module1.rs
pub fn func() -> String {
    "ABC".to_string()
}
```

```rust:src/module2.rs
pub fn func() -> String {
    "DEF".to_string()
}
```

この時、`module2::func`関数から`module1::func`関数呼び出すには以下の方法があります。

#### 絶対パス

`crate`から始まるパスで呼び出します。

```rust:src/module2.rs
pub fn func() -> String {
    format!("{}DEF", crate::module1::func())
}
```

`use`を使うと以下の様になります。

```rust:module2.rs
use crate::module1;

pub fn func() -> String {
    format!("{}DEF", module1::func())
}
```

#### 相対パス

モジュールの階層構造は以下の様になります。

```:モジュールの階層構造
crate
 ┣━ main
 ┣━ module1
 ┃   ┗━ func
 ┗━ module2
     ┗━ func
```

`module2::func`から見ると`module1`は1つ上の階層にあります。
親モジュールの階層へアクセスするには`super`を使います。

```rust:src/module2.rs
pub fn func() -> String {
    format!("{}DEF", super::module1::func())
}
```

相対パスでも`use`を使うことができます。

```rust:src/module2.rs
use super::module1;

pub fn func() -> String {
    format!("{}DEF", module1::func())
}
```

## ディレクトリで階層を分けた場合

上記は同じ階層下でファイル分割した例でした。
次はディレクトリで階層を分けた場合を説明します。

```
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┗━ submodule
        ┗━ module1.rs
```

```rust:src/main.rs
mod submodule;

fn main() {
    println!("{}", submodule::module1::func());
}
```

```rust:src/submodule/module1.rs
pub fn func() -> String {
    "ABC".to_string()
}
```

上記の構成で問題なさそうですがエラーになります。
ディレクトリと同じ階層にディレクトリ名と同じ`rs`ファイルが必要です。

```
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┣━ submodule.rs # このファイルが必要
    ┗━ submodule
        ┗━ module1.rs
```

このファイル内ではディレクトリ直下のモジュールを宣言します。
これでモジュールが認識されます。

```rust:src/submodule.rs
pub mod module1;
```

### `mod.rs`を置く方法

2015 editionのRustではフォルダ内に`mod.rs`を追加していました。
しかし現在ではこの方法は非推奨となっています。

```
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┗━ submodule
        ┣━ mod.rs # このファイルを追加する
        ┗━ module1.rs
```

```rust:src/submodule/mod.rs
pub mod module1;
```

## 参考

https://doc.rust-jp.rs/book-ja/ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html

https://blog.foresta.me/posts/rust-modules/