8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

はじめに

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

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

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

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

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 (相対パス)

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

モジュールの階層構造

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

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

useキーワード

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

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モジュール内にあると認識されます。

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

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

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
src/main.rs
mod module1;
mod module2;

fn main() {
    println!("{}", module1::func());
    println!("{}", module2::func());
}
src/module1.rs
pub fn func() -> String {
    "ABC".to_string()
}
src/module2.rs
pub fn func() -> String {
    "DEF".to_string()
}

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

絶対パス

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

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

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

module2.rs
use crate::module1;

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

相対パス

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

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

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

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

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

src/module2.rs
use super::module1;

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

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

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

┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
    ┣━ main.rs
    ┗━ submodule
        ┗━ module1.rs
src/main.rs
mod submodule;

fn main() {
    println!("{}", submodule::module1::func());
}
src/submodule/module1.rs
pub fn func() -> String {
    "ABC".to_string()
}

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

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

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

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
src/submodule/mod.rs
pub mod module1;

参考

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?