はじめに
Rustにはモジュールというスコープに名前を付ける機能があります。
自分はこのモジュールについて理解せずにファイルを分割してエラーで苦労しました。
同じファイル内でのモジュール
mod モジュール名 {}でモジュールを定義できます。
モジュール内の要素はデフォルトでは非公開です。
外部に公開する場合はpubを付ける必要があります。
モジュール内の要素へアクセスする際は::を使います。
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キーワードを使うとパスを省略して呼び出すことができます。
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モジュール内にあると認識されます。
pub fn func() -> String {
"ABC".to_string()
}
またファイルを分割した場合、必ず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
mod module1;
mod module2;
fn main() {
println!("{}", module1::func());
println!("{}", module2::func());
}
pub fn func() -> String {
"ABC".to_string()
}
pub fn func() -> String {
"DEF".to_string()
}
この時、module2::func関数からmodule1::func関数呼び出すには以下の方法があります。
絶対パス
crateから始まるパスで呼び出します。
pub fn func() -> String {
format!("{}DEF", crate::module1::func())
}
useを使うと以下の様になります。
use crate::module1;
pub fn func() -> String {
format!("{}DEF", module1::func())
}
相対パス
モジュールの階層構造は以下の様になります。
crate
┣━ main
┣━ module1
┃ ┗━ func
┗━ module2
┗━ func
module2::funcから見るとmodule1は1つ上の階層にあります。
親モジュールの階層へアクセスするにはsuperを使います。
pub fn func() -> String {
format!("{}DEF", super::module1::func())
}
相対パスでもuseを使うことができます。
use super::module1;
pub fn func() -> String {
format!("{}DEF", module1::func())
}
ディレクトリで階層を分けた場合
上記は同じ階層下でファイル分割した例でした。
次はディレクトリで階層を分けた場合を説明します。
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
┣━ main.rs
┗━ submodule
┗━ module1.rs
mod submodule;
fn main() {
println!("{}", submodule::module1::func());
}
pub fn func() -> String {
"ABC".to_string()
}
上記の構成で問題なさそうですがエラーになります。
ディレクトリと同じ階層にディレクトリ名と同じrsファイルが必要です。
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
┣━ main.rs
┣━ submodule.rs # このファイルが必要
┗━ submodule
┗━ module1.rs
このファイル内ではディレクトリ直下のモジュールを宣言します。
これでモジュールが認識されます。
pub mod module1;
mod.rsを置く方法
2015 editionのRustではフォルダ内にmod.rsを追加していました。
しかし現在ではこの方法は非推奨となっています。
┣━ Cargo.lock
┣━ Cargo.toml
┗━ src
┣━ main.rs
┗━ submodule
┣━ mod.rs # このファイルを追加する
┗━ module1.rs
pub mod module1;
参考