モジュールシステム
コードを整理する「モジュール」について学びます。
モジュールとは
モジュールはコードを論理的に分割する仕組みです。
my_project/
├── src/
│ ├── main.rs # エントリーポイント
│ ├── lib.rs # ライブラリクレートのルート
│ ├── utils.rs # utilsモジュール
│ └── models/
│ ├── mod.rs # modelsモジュールのルート
│ └── user.rs # models::userサブモジュール
基本的なモジュール定義
同一ファイル内
mod greetings {
pub fn hello() {
println!("Hello!");
}
fn private_function() {
println!("This is private");
}
}
fn main() {
greetings::hello();
// greetings::private_function(); // エラー!プライベート
}
別ファイルに分割
src/main.rs
mod utils; // src/utils.rs を読み込む
fn main() {
utils::greet();
}
src/utils.rs
#![allow(unused)]
fn main() {
pub fn greet() {
println!("Hello from utils!");
}
}
pub(公開)キーワード
デフォルトはプライベート。pubで公開します。
mod outer {
pub mod inner {
pub fn public_function() {
println!("公開関数");
}
fn private_function() {
println!("非公開関数");
}
}
}
fn main() {
outer::inner::public_function();
}
構造体フィールドの公開
mod models {
pub struct User {
pub name: String, // 公開
email: String, // 非公開
}
impl User {
pub fn new(name: String, email: String) -> User {
User { name, email }
}
pub fn email(&self) -> &str {
&self.email
}
}
}
fn main() {
let user = models::User::new(
String::from("太郎"),
String::from("taro@example.com"),
);
println!("名前: {}", user.name);
// println!("メール: {}", user.email); // エラー!非公開
println!("メール: {}", user.email()); // メソッド経由でOK
}
use キーワード
長いパスを短縮します。
mod models {
pub mod user {
pub struct User {
pub name: String,
}
}
}
// useでパスを短縮
use models::user::User;
fn main() {
let u = User { name: String::from("太郎") };
// models::user::User と書かなくてよい
}
複数のインポート
#![allow(unused)]
fn main() {
use std::collections::{HashMap, HashSet};
use std::io::{self, Read, Write};
}
エイリアス(as)
use std::collections::HashMap as Map;
fn main() {
let mut m: Map<String, i32> = Map::new();
}
再エクスポート(pub use)
#![allow(unused)]
fn main() {
mod models {
pub mod user {
pub struct User { pub name: String }
}
}
// 外部からmodels::Userでアクセス可能にする
pub use models::user::User;
}
ディレクトリ構造
方法1: mod.rs を使う
src/
├── main.rs
└── models/
├── mod.rs # モジュールのルート
└── user.rs
src/main.rs
#![allow(unused)]
fn main() {
mod models;
use models::User;
}
src/models/mod.rs
#![allow(unused)]
fn main() {
mod user;
pub use user::User;
}
src/models/user.rs
#![allow(unused)]
fn main() {
pub struct User {
pub name: String,
}
}
方法2: ファイル名でモジュール(Rust 2018以降)
src/
├── main.rs
├── models.rs # mod models の定義
└── models/
└── user.rs # mod models::user の定義
src/models.rs
#![allow(unused)]
fn main() {
pub mod user;
pub use user::User;
}
クレート(Crate)
クレートはRustのコンパイル単位です。
- バイナリクレート: 実行可能ファイル(
main.rs) - ライブラリクレート: 他のコードから使うライブラリ(
lib.rs)
外部クレートの使用
Cargo.toml
[dependencies]
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
src/main.rs
use rand::Rng;
fn main() {
let n = rand::thread_rng().gen_range(1..100);
println!("{}", n);
}
実践的なプロジェクト構造
my_app/
├── Cargo.toml
└── src/
├── main.rs # エントリーポイント
├── lib.rs # ライブラリ(オプション)
├── config.rs # 設定モジュール
├── error.rs # エラー定義
├── models/
│ ├── mod.rs
│ ├── user.rs
│ └── post.rs
└── handlers/
├── mod.rs
├── auth.rs
└── api.rs
まとめ
| 概念 | 説明 |
|---|---|
mod | モジュールを定義/インポート |
pub | 公開する(デフォルトは非公開) |
use | パスを短縮 |
pub use | 再エクスポート |
| クレート | コンパイル単位(binary/library) |
確認テスト
Q1. Rustのアイテム(関数、構造体など)のデフォルトの可視性は?
正解: B) Rustではすべてのアイテムはデフォルトで非公開です。
pubキーワードで明示的に公開する必要があります。
Q2. use std::collections::{HashMap, HashSet};は何をしている?
正解: B) 中括弧
{}を使って、同じパスから複数のアイテムを一度にインポートしています。
Q3. 以下のコードがコンパイルエラーになる理由は?mod secret { fn hidden() { println!("Hidden!"); } } fn main() { secret::hidden(); }
正解: C)
hidden関数はpubがないため非公開です。モジュール外からアクセスするにはpub fn hidden()のように公開する必要があります。
Q4. pub useの役割は?
正解: A)
pub useは内部のアイテムを再エクスポートし、外部からより短いパスでアクセスできるようにします。
Q5. Rustにおける「クレート(Crate)」とは?
正解: D) クレートはRustのコンパイル単位で、バイナリクレート(実行可能ファイル)またはライブラリクレート(他のコードから使用)があります。
次のドキュメント: 06_error_handling_adv.md