はじめに
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;
参考