[Rust]パッケージ・クレート・モジュールについて

Rust

Rustもようやく多少は書き慣れてきたので、今の段階でわかっているパッケージやモジュールのあれこれをまとめます。

参考ページ
Managing Growing Projects with Packages, Crates, and Modules - The Rust Programming Language

 Androidアプリを作成しました。
 感情用のメモ帳です。

スポンサーリンク
スポンサーリンク

相関図

パッケージ・クレート・モジュールを簡単な図にすると、次のようになります。

クレートは「~.rs」ファイルのことです。

クレート内にモジュールを定義し、コードをブロックとしてまとめることもできます。

cargoを使って新しいプロジェクトを作成します。

$ cargo new my-project
     Created binary (application) `my-project` package
$ cd my-project/
$ ls
Cargo.lock  Cargo.toml  src
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"

パッケージとして「my-project」が作成されました。

クレート

$ tree .
.
├── Cargo.toml
└── src
    └── main.rs

1 directory, 2 files

特にオプションを付けずに「cargo new」コマンドを実行すると、「main.rs」が作成されます。
これがバイナリクレートで、ここ記されたコードがデフォルトで「cargo build」コマンドによりコンパイルされ、バイナリが作成されます。

またバイナリでないクレートを作るには、src内に「lib.rs」を手動で作成するか、「cargo new」コマンドに、オプション「--lib」をつけて実行します。
このファイルがライブラリのルート(起点)となるクレートになります。

$ tree src
src
├── lib.rs
└── main.rs

0 directories, 2 files
pub fn root_func() {}
fn main() {
    my_project::root_func();
}

lib.rsの機能をmainに持ち込むには、パッケージ名を使います。

パッケージ名::関数名

今回のパッケージは「my-project」にしましたが、呼び出す際にハイフンは使えないため、アンダースコアになっていて「my_project」で呼び出します。

モジュール

キーワード「mod」を使ってできることは2つあります。

  1. モジュールの定義
  2. モジュールの取り込み

モジュールの定義

クレート内で「mod」を使ってモジュールを定義すると、コードをひとまとまりのブロックとして分けることができます。

pub fn root_func() {
    println!("Root");
}

pub mod branch {
    pub fn branch_func() {
        println!("Root / Branch");
    }
}
fn main() {
    my_project::root_func();
    my_project::branch::branch_func();
}

mainでは、パッケージ名::モジュール名::関数名のようにして呼び出し可能です。

また、モジュール内でさらにモジュールの定義でき、

pub mod branch {
    pub fn branch_func() {
        println!("Root / Branch");
    }

    pub mod leaf  {
        pub fn leaf_func() {
            println!("Root / Branch / Leaf");
        }
    }
}
use my_project::branch;

fn main() {
    my_project::root_func();
    branch::branch_func();
    branch::leaf::leaf_func();
    // 出力
    // Root
    // Root / Branch
    // Root / Branch / Leaf
}

このように呼び出すことができます。

lib.rsから内側にあるモジュールの機能を呼びたいなら、呼び出すところから見て絶対パスのcrateやself、モジュール名からたどっていて記述し、モジュールから参照したい場合には、同じくcrate、selfのほか、superなどを使って呼び出します。

モジュールの取り込み

「mod」キーワードでできることのもうひとつがモジュールの取り込みで、クレートやモジュールが肥大化してきたときに有効です。

前の項目のbranchモジュールの内容を「src/branch.rs」を作成して移動します。

pub fn branch_func() {
    println!("Root / Branch");
}

pub mod leaf  {
    pub fn leaf_func() {
        println!("Root / Branch / Leaf");
    }
}

mod branch{}で囲っていたところを除き、ネストを減らした形です。

そして「lib.rs」に一文を加えます。

pub mod branch;

pub fn root_func() {
    println!("Root");
}

先程のブロックとして定義していた{}ではなく、;を使ってbranch.rsの内容を取り込んでいます。

こうすることで、「lib.rs」内で「branch.rs」の内容を定義しているのと同じことになります。

なので呼び出しは、

use my_project::branch;

fn main() {
    my_project::root_func();
    branch::branch_func();
    branch::leaf::leaf_func();
}

先程と同じ記述で動作します。

ライブラリクレートを経由せず、「main.rs」に直接取り込むことも可能です。

mod branch;

fn main() {
    my_project::root_func();
    crate::branch::branch_func();
    self::branch::leaf::leaf_func();
}

crateやselfを使って統一していないのは例示するためで、branchから書いても問題ありません。

タイトルとURLをコピーしました