モジュールとファイルシステム

# まえがき

この記事はRUSTチュートリアルをZerobillbank社内メンバー（有志）で勉強がてら、可能な限りわかりやすく内容を書き出す企画の一部です。  

初学者のため（略）という免責を打ちつつ間違いなどあればコメントで教えていただけますと一同嬉しく思います！

# Reference

- [PlayGround](https://play.rust-lang.org/)
- [チュートリアルページ](https://doc.rust-jp.rs/book/second-edition/ch07-01-mod-and-the-filesystem.html)

# 概要
ライブラリとする場合と通常プロジェクトをNode.jsでは特段差別化はしていませんが、
Rustではプロジェクト作成段階から作成方法が異なります。  
  
Rustでは通常のプロジェクトを `バイナリクレート` と呼び、
ライブラリは `ライブラリクレート` と呼び区別します。

本章ではライブラリクレートについて、プロジェクトの生成方法から触れていきます。

# ライブラリクレートの始め方

ライブラリクレートの作成方法は、通常のバイナリクレートと同様にcargoコマンドで行います。

```bash
$ cargo new {pj-name} --lib
```

通常では --binであるオプションが --libに変更されるだけですね。

# プロジェクトの構成について

ライブラリクレートではバイナリクレートと比べた際に生成されるファイル名も内容も異なります。

[ フォルダとファイル構成 ]

```
.
├── Cargo.toml
└── src
    └── lib.rs
```

通常では `main.rs` が生成されるはずですが、ライブラリクレートにおいては `lib.rs` が生成されます。

## 生成ファイルの中身

生成ファイルの中身はこんな感じ

```rust
#[cfg(test)] // -> ここは「superを使用して親モジュールにアクセスする」で説明
mod tests {
    #[test] // -> ここは「superを使用して親モジュールにアクセスする」で説明
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
```

上記のように単体ファイルとして実行可能な Hello world バイナリではなく、空のテストを生成しています。
もちろん単体実行できないわけですから cargo runではなく、cargo build をすることになります。

# ライブラリクレートの書き方

ここからは元記事から抜粋して進めます。
  
今回実装するライブラリクレートは `communicator` という、外部と通信をする？ものみたいです。
まずライブラリとして記述するプロジェクトでは、モジュールであるという宣言として `mod` を使用します。

```rust
mod network {
    fn connect() {
    }
}
```

network という名前空間に connectという関数を用意しました。
このconnect関数を利用する時、外部からの呼び出しは `network::connect()` という記述になります。
また、modは一つのファイルに複数記述することが可能です。

```rust
mod network {
    fn connect() {
    }
}

mod client {
    fn connect() {
    }
}
```

上記の例では `network` と `client` という二つの名前空間があり、
それぞれの関連性はある場合もあるでしょうし、ない場合もあるでしょう。

推測できませんね。  
  
例えばこれが、networkの中で内包するする１機能であった場合（関連性があるという意味です）、
networkの名前空間の中にclientの名前空間をネストして記述することも可能なようです。

```rust
mod network {
  fn connect() {
  }
  mod client {
    fn connect() {
    }
  }
}
```

## modを外部ファイルに切り出す

関数肥大化すれば、名前空間が増えれば必然的に名前空間ごとにファイルを切り出す必要が出てきます。
まずは以下のようなコードがあったとします。

```rust
mod client {
    fn connect() {
    }
}

mod network {
    fn connect() {
    }

    mod server {
        fn connect() {
        }
    }
}
```

`mod client` を切り出した場合の記述は以下です。  

```rust
mod client;

mod network {
    fn connect() {
    }

    mod server {
        fn connect() {
        }
    }
}
```

clientモジュールの中身を抽出するが、宣言はsrc/lib.rsに残したままです。
この書き方は ブロックをセミコロンで置換した と表現するようです。
続いて切り出したclientモジュールをファイルに書き出しましょう。
  
【注意】  
  
```
srcディレクトリに、またはlib.rsの配下に作成してください。
Rustで外部ファイルを読み込む場合は同一、または下の階層しか読み込めません。
```

今回は `src/client.rs` というファイルを作成し、以下を実装します。

```rust
fn connect() {
}
```

名前空間はセミコロンで置換されているので、切り出し先ファイルで宣言する必要はありません。関数のみの記述です。

では続いてnetworkモジュールを切り出します。
今回は `src/network/mod.rs` になります。
  
```rust
fn connect() {
}

mod server;
```

ネストしていたservevrモジュールが残ってしまっていますので、こいつも切り出します。
  
`src/network/server/mod.rs`  
  
```rust
fn connect() {
}
```

最終的な構成は以下です。

```
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── client
│   │   └── mod.rs
│   ├── lib.rs
│   └── network
│       ├── mod.rs
│       └── server
│           └── mod.rs
```

# モジュール内の関数をpublicにする

チュートリアルページ：https://doc.rust-jp.rs/book/second-edition/ch07-02-controlling-visibility-with-pub.html

現段階で `cargo build` によるコンパイルは通ります。
しかし、使用されていない関数が存在しているため警告が表示されているかと思います。
  
```
warning: function is never used: `connect`
 --> src/client.rs:1:1
  |
1 | / fn connect() {
2 | | }
  | |_^
  |
  = note: #[warn(dead_code)] on by default

warning: function is never used: `connect`
 --> src/network/mod.rs:1:1
  |
1 | / fn connect() {
2 | | }
  | |_^

warning: function is never used: `connect`
 --> src/network/server.rs:1:1
  |
1 | / fn connect() {
2 | | }
  | |_^
```

上記で警告が出ている関数は **外部から呼び出す** ことを前提にしたものであり、
今回のプロジェクト内で呼び出すことはありません。

これらの外部から呼び出すための関数は `pub` 修飾子をつけてあげる必要があります。
  
```lib.rs
pub mod client;

pub mod network;
```

```src/client.rs
pub fn connect() {
}
```

```src/network/mod.rs
pub fn connect() {
}

mod server;
```

上記のように、`lib.rs` で読み込んでいる `client`, `network` それぞれの `pub` 化、
そしてそれぞれpub化した関数自体の `pub` 化を行うことで警告が出なくなり、
外部からの呼び出しも可能になります。