RustのモジュールシステムとCargo:コードの整理とプロジェクト管理
モジュールシステムは、Rustの「コードのアドレス指定方式」です。建物の住所と同じように、これにより、コードの各部分の場所を正確に特定し、外部からどの部分にアクセスできるかを制御することができます。
もし大規模なプロジェクトを都市に例えるなら、モジュール(mods)は地区、ファイルは建物、関数は部屋に相当するでしょう。Cargoは都市の行政機関のようなもので、道路の建設、維持管理、品質の確保を担当しています。モジュールシステムがなければ、コードは「集落」がごちゃ混ぜになったような状態になってしまうでしょう。
1. 学習内容
modキーワード定義モジュールとネストされたモジュールpub可視性制御—親モジュール、子モジュール、および同階層モジュールのアクセスルールuseパスのインポートおよびsuper/crateの相対パスCargo.toml依存関係管理とセマンティック・バージョニング(SemVer)cargo build/test/bench/doc共通コマンド- ワークスペースのマルチパッケージ管理と、
lib.rsとmain.rsの役割分担
2. マンションの部屋番号付けの仕組みにまつわるエピソード
(1) 苦難:家番号のない街
トムは新築のマンションに引っ越したが、そこには家番号の付け方がないことに気づいた。
- 彼は3号館の502号室を探していたが、どの建物もどれも同じように見えた。
- 食事を配達する際、配達員は電話をかけて「どちらの建物におられますか?」と尋ねなければなりません。
- 管理事務所からの通知:「3号棟5階にお住まいの皆様、荷物のお受け取りにお越しください」――しかし、実際には3号棟5階には6世帯が住んでいます。
- さらに悪いことに、新しい住民たちは家の番号を「アリババ」に変えてしまい、住所表記システム全体が機能しなくなってしまった。
「建物・ユニット・アパートというように、標準化された家屋番号の付け方があれば素晴らしいのですが……」
(2) Rustのモジュールシステムへのアプローチ
Apartment(Crate) → A building
Building Name(crate name) → Building Number
Unit(Module) → Apartment Building Entrance
Room Number(Function) → Specific Rooms
// File Structure Correspondence:
// src/
// main.rs → Apartment Lobby(Entrance)
// building/
// mod.rs → Building Information
// unit_1/
// mod.rs → 1 Unit
// room_501.rs → 501 Room
// room_502.rs → 502 Room
// In Rust, through mod and pub, precisely control who can access what
mod building {
pub mod unit_1 {
pub fn room_501() -> &'static str {
"501 Room: Tom Home"
}
fn room_502() -> &'static str {
"502 Room: Private Space" // Default: Private, not visible externally
}
}
}
fn main() {
// Access via the full path
println!("{}", building::unit_1::room_501());
// println!("{}", building::unit_1::room_502()); // ❌ Private Functions,Compilation Error
}
Rustのモジュールシステムは、マンションの住所体系のようなものです。
crateは建物全体を表し、modは棟を表し、fnは各住戸を表します。pubは、どの住戸に外へ通じるドアがあるかを制御します。pubがない住戸はプライベートな空間であり、部外者は自由に出入りできません。
3. 基本概念
(1) モジュールシステムとパス
graph TB
A[Rust Modular System] --> B[mod Definition]
A --> C[pub Visibility]
A --> D[use Path Import]
A --> E[Cargo Project Management]
B --> B1["mod Module Name { ... }"]
B --> B2["mod Module Name; // From a file"]
C --> C1["pub: Visible to the public"]
C --> C2["pub(crate): crate only, visible inside"]
C --> C3["pub(super): Visible only to the parent module"]
C --> C4["No pub: Private"]
D --> D1["use crate::a::b::c;"]
D --> D2["use super::module;"]
D --> D3["use self::module;"]
E --> E1["Cargo.toml Dependency"]
E --> E2["cargo build / test"]
E --> E3["workspace Multiple Packages"]
E --> E4["lib.rs vs main.rs"]
(2) 可視性ルールの比較
| 公開範囲 | キーワード | アクセス権限 | 類似例 |
|---|---|---|---|
| 非公開 | なし(デフォルト) | 現在のモジュールおよびサブモジュール | 寝室に入ることができるのは家族のみ |
| 親モジュールから表示可能 | pub(super) |
親モジュール | 上下階の隣人が立ち寄れる |
| クレート内で表示されるもの | pub(crate) |
現在のクレート内のすべてのモジュール | 居住者はコミュニティのゲートから入ることができます |
| 公開 | pub |
すべての外部クレート | 誰でもモールに入ることができる |
(3) パスの種類
| パス種別 | プレフィックス | 例 | 説明 |
|---|---|---|---|
| 絶対パス | crate:: |
crate::utils::helper::foo |
クレートのルートから |
| 相対パス | self:: |
self::helper::foo |
現在のモジュールから |
| 相対パス | super:: |
super::helper::foo |
親モジュールから |
| 外部パス | パッケージ名 | serde::Serialize |
外部のcrateから開始 |
(4) 一般的な貨物コマンドのクイックリファレンス
| コマンド | 機能 | 一般的なオプション |
|---|---|---|
cargo new |
新規プロジェクトの作成 | --lib (ライブラリプロジェクト) |
cargo build |
プロジェクトのコンパイル | --release (最適化コンパイル) |
cargo run |
コンパイルして実行 | --bin name (バイナリを指定) |
cargo check |
コンパイルエラーを素早く確認 | ビルドよりも高速;バイナリは生成されない |
cargo test |
テストを実行 | test_name (指定されたテスト) |
cargo doc |
ドキュメントを生成 | --open (ブラウザが自動的に開きます) |
cargo clippy |
コードのリンティングチェック | -W clippy::all |
cargo fmt |
コードの書式設定 | --check (確認のみ。変更しないでください) |
cargo add |
依存関係を追加 | --features xxx |
cargo update |
依存関係ロックファイルを更新 | Cargo.lock を更新 |
cargo publish |
crates.io に公開 | まずログインする必要があります |
cargo clean |
ビルドアーティファクトのクリーンアップ | target/ ディレクトリの削除 |
4. モジュールとCargoの例
(1) ▶ サンプル:モジュールの定義と pub の可視性 (難易度 ⭐)
// ============================================
// Module Nesting、pub Visibility、Path Access
// Demo: The restaurant's kitchen is not visible to customers, but visible to servers
// ============================================
// Defining the Restaurant Module
mod restaurant {
// Public: Customers may enter the restaurant
pub struct Menu {
pub name: String,
price: f64, // Default: Private,Not visible externally
}
impl Menu {
// Public Constructor
pub fn new(name: &str, price: f64) -> Menu {
Menu {
name: name.to_string(),
price,
}
}
// Public Methods: Get Price
pub fn get_price(&self) -> f64 {
self.price
}
}
// Public: Customers can order food
pub fn order_food(item: &str) -> String {
// Private: Kitchen operations are not visible to customers
let prepared = prepare_in_kitchen(item);
format!("Your {} Ready: {}", item, prepared)
}
// Private: Customers are not allowed in the kitchen.
fn prepare_in_kitchen(item: &str) -> String {
format!("[Kitchen] {} Cooking in progress...", item)
}
// Nested Modules: Inside the Kitchen
mod kitchen {
// Private Storage Area
pub struct Storage {
pub items: Vec<String>,
}
impl Storage {
pub fn new() -> Storage {
Storage {
items: vec![
"Vegetables".to_string(),
"Meat".to_string(),
"Seasonings".to_string(),
],
}
}
}
}
}
fn main() {
// Accessing Public Module Members
let dish = restaurant::order_food("Kung Pao Chicken");
println!("{}", dish);
// Create a public struct
let menu_item = restaurant::Menu::new("Kung Pao Chicken", 38.0);
println!("Dishes: {}, Price: {:.1} yuan", menu_item.name, menu_item.get_price());
// The following code cannot be compiled(Uncomment this line to try it):
// println!("Chef Information: {}", restaurant::prepare_in_kitchen("Kung Pao Chicken")); // ❌ Private Functions
// println!("Price: {}", menu_item.price); // ❌ Private Fields
// let storage = restaurant::kitchen::Storage::new(); // ❌ kitchen The module is private.
}
出力:
Your Kung Pao Chicken Ready: [Kitchen] Kung Pao Chicken Cooking in progress...
Dishes: Kung Pao Chicken, Price: 38.0 yuan
モジュールの可視性ルールは、レストランの物理的なレイアウトに例えることができます。顧客(外部コード)はダイニングルーム(
pubモジュール)にしか入ることができず、厨房(プライベートモジュール)には立ち入ることができません。厨房(prepare_in_kitchen)で行われている作業は、外部からはまったく見えません。これがカプセル化です。
(2) ▶ サンプル:use の経路と super/crate (難易度: ⭐⭐)
// ============================================
// use Keyword Import Path、super and crate Relative Path
// Simulation: Company Organizational Structure - Department→Group→Employees
// ============================================
// Top-Level Module: Company
mod company {
// Engineering Department
pub mod engineering {
pub fn team_name() -> &'static str {
"Engineering Department"
}
// Front-End Team
pub mod frontend {
pub fn member_count() -> u32 {
5
}
// Use super to access the parent module (engineering)
pub fn full_info() -> String {
format!("{} Front-End Team, {} people", super::team_name(), member_count())
}
}
// Backend Team
pub mod backend {
pub fn member_count() -> u32 {
8
}
// Usage super Access the Parent Module
pub fn full_info() -> String {
format!("{} Backend Team, {} people", super::team_name(), member_count())
}
}
}
// Marketing Department
pub mod marketing {
pub fn team_name() -> &'static str {
"Marketing Department"
}
// Usage crate Path Access from the Root
pub fn total_employees() -> u32 {
// From crate root, access begins
crate::company::engineering::frontend::member_count()
+ crate::company::engineering::backend::member_count()
+ self::member_count()
}
fn member_count() -> u32 {
6
}
}
}
// Usage use Import Path——Simplify the call
use company::engineering::frontend;
use company::engineering::backend;
use company::marketing;
fn main() {
// Method 1: Full path (Not recommended, too long to write)
println!("{}", company::engineering::frontend::full_info());
// Method 2: Call directly after use import (Recommended)
println!("{}", frontend::full_info());
println!("{}", backend::full_info());
// Introduction marketing Module
println!("Number of employees in the Marketing Department: {}", marketing::member_count());
// Usage crate Path Access
println!("Total Number of Employees: {}", marketing::total_employees());
// Usage as Avoiding Alias Conflicts
use company::engineering as eng;
println!("Department: {}", eng::team_name());
}
出力:
Engineering Department Front-End Team, 5 people
Engineering Department Backend Team, 8 people
Number of employees in the Marketing Department: 6
Total Number of Employees: 19
Department: Engineering Department
useこれは「家番号」へのショートカットを作成するようなもので、毎回完全な住所を入力する必要がなくなりますcompany::engineering::frontend::full_info()。superは「1つ上のレベルへ移動」(親モジュール)を意味し、crateは「建物の入り口に戻る」(ルート)を意味します。asキーワードを使用することで、パスに別名を割り当て、名前の重複による競合を解決することができます。
(3) ▶ サンプル:Cargo.toml における依存関係管理とプロジェクト構造 (難易度: ⭐⭐)
// ============================================
// Simulation Cargo Project Structure + Dependency Management
// Demo:lib.rs and main.rs Division of Labor、Using External Dependencies
// ============================================
// Note: This example demonstrates the code in lib.rs
// Actual Cargo.toml See the note below for the contents of the document.
// ============================================
// Cargo.toml Content (Simulation):
// ============================================
// [package]
// name = "my-toolkit"
// version = "0.1.0"
// edition = "2021"
//
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// serde_json = "1.0"
// chrono = "0.4"
// regex = "1.10"
//
// [dev-dependencies]
// rand = "0.8"
//
// [profile.release]
// opt-level = 3
// ============================================
// Tools Module: Date Handling
pub mod date_utils {
pub fn format_today() -> String {
// Used in actual projects chrono::Local::now()
"2026-07-03".to_string()
}
pub fn is_weekend(day: &str) -> bool {
day.ends_with("Saturday") || day.ends_with("Sunday")
}
}
// Tools Module: String Processing
pub mod string_utils {
/// Verify the email address format (Simulating Regular Expression Matching)
pub fn validate_email(email: &str) -> bool {
// Simplified Verification: Use regex crate in practice
email.contains('@') && email.contains('.')
}
/// Remove non-alphanumeric characters (Simulation)
pub fn sanitize(input: &str) -> String {
input.chars()
.filter(|c| c.is_alphanumeric() || *c == ' ')
.collect()
}
}
// Tools Module: Mathematical Calculations
pub mod math_utils {
/// Calculate the nth term of the nth term of the Fibonacci sequence
pub fn fibonacci(n: u32) -> u64 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
/// Determining Whether a Number Is Prime
pub fn is_prime(n: u32) -> bool {
if n < 2 {
return false;
}
let limit = (n as f64).sqrt() as u32;
for i in 2..=limit {
if n % i == 0 {
return false;
}
}
true
}
}
// Test Module (Using #[cfg(test)] Conditional Compilation)
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_email() {
assert!(string_utils::validate_email("user@example.com"));
assert!(!string_utils::validate_email("invalid"));
}
#[test]
fn test_fibonacci() {
assert_eq!(math_utils::fibonacci(0), 0);
assert_eq!(math_utils::fibonacci(1), 1);
assert_eq!(math_utils::fibonacci(10), 55);
}
#[test]
fn test_is_prime() {
assert!(math_utils::is_prime(17));
assert!(!math_utils::is_prime(1));
assert!(!math_utils::is_prime(4));
}
#[test]
fn test_sanitize() {
assert_eq!(string_utils::sanitize("hello@world!"), "hello world");
}
}
// ============================================
// main.rs The code in (Simulation):
// ============================================
// use my_toolkit::{
// date_utils,
// string_utils,
// math_utils,
// };
//
// fn main() {
// println!("Today's Date: {}", date_utils::format_today());
// println!("Email Verification: {}", string_utils::validate_email("test@example.com"));
// println!("Prime Number Check: {}", math_utils::is_prime(17));
// }
fn main() {
// Demonstration of Each Tool's Functions
println!("=== Tool Library Demo ===");
// Date Tools
println!("Today: {}", date_utils::format_today());
println!("Is it the weekend?: {}", date_utils::is_weekend("Saturday"));
// String Tools
println!("Email Verification test@example.com: {}", string_utils::validate_email("test@example.com"));
println!("Email Verification invalid: {}", string_utils::validate_email("invalid"));
println!("Purification 'hello@world!': {}", string_utils::sanitize("hello@world!"));
// Mathematical Tools
println!("Fibonacci #10: {}", math_utils::fibonacci(10));
println!("17 Is it a prime number?: {}", math_utils::is_prime(17));
println!("4 Is it a prime number?: {}", math_utils::is_prime(4));
println!("=== End of Presentation ===");
// Instructions for Running the Test (Use cargo test in actual projects)
println!("Usage `cargo test` Run Unit Tests");
}
出力:
=== Tool Library Demo ===
Today: 2026-07-03
Is it the weekend?: true
Email Verification test@example.com: true
Email Verification invalid: false
Purification 'hello@world!': hello world
Fibonacci #10: 55
17 Is it a prime number?: true
4 Is it a prime number?: false
=== End of Presentation ===
Usage `cargo test` Run Unit Tests
実際のプロジェクトにおける標準的な構成:
lib.rsにはライブラリコード(パブリック API)が含まれ、main.rsには実行可能ファイルのエントリポイント(ライブラリを使用するもの)が含まれます。Cargo.tomlは依存関係を管理し、[dependencies]には本番環境の依存関係が、[dev-dependencies]にはテスト/ビルドツールの依存関係が含まれます。cargo testは、#[test]でマークされた関数を自動的に検出して実行します。
(4) ▶ サンプル:よく使われるカーゴコマンドとワークスペース(難易度 ⭐⭐⭐)
// ============================================
// Cargo Common Commands and workspace Multi-Package Management
// Simulation: One "Task Manager" workspace Project
// ============================================
// ============================================
// Top Floor Cargo.toml (workspace):
// ============================================
// [workspace]
// members = [
// "task-core", // Core Library
// "task-cli", // CLI Tools
// "task-web", // Web Interface
// ]
//
// [workspace.package]
// version = "1.0.0"
// edition = "2021"
// ============================================
// ============================================
// task-core/Cargo.toml:
// ============================================
// [package]
// name = "task-core"
// version.workspace = true
// edition.workspace = true
//
// [dependencies]
// serde = { version = "1.0", features = ["derive"] }
// chrono = "0.4"
// ============================================
// Simulation task-core Library code
pub mod task_core {
use std::collections::HashMap;
/// Task Priority
#[derive(Debug, Clone, PartialEq)]
pub enum Priority {
Low,
Medium,
High,
Urgent,
}
/// Task Status
#[derive(Debug, Clone, PartialEq)]
pub enum Status {
Todo,
InProgress,
Done,
Cancelled,
}
/// Core Task Structure
#[derive(Debug, Clone)]
pub struct Task {
pub id: u64,
pub title: String,
pub priority: Priority,
pub status: Status,
pub tags: Vec<String>,
}
impl Task {
pub fn new(id: u64, title: &str, priority: Priority) -> Task {
Task {
id,
title: title.to_string(),
priority,
status: Status::Todo,
tags: Vec::new(),
}
}
pub fn add_tag(&mut self, tag: &str) {
self.tags.push(tag.to_string());
}
pub fn is_completed(&self) -> bool {
self.status == Status::Done || self.status == Status::Cancelled
}
}
/// Task Manager
pub struct TaskManager {
tasks: HashMap<u64, Task>,
next_id: u64,
}
impl TaskManager {
pub fn new() -> TaskManager {
TaskManager {
tasks: HashMap::new(),
next_id: 1,
}
}
pub fn create_task(&mut self, title: &str, priority: Priority) -> u64 {
let id = self.next_id;
self.next_id += 1;
let task = Task::new(id, title, priority);
self.tasks.insert(id, task);
id
}
pub fn get_task(&self, id: u64) -> Option<&Task> {
self.tasks.get(&id)
}
pub fn complete_task(&mut self, id: u64) -> bool {
if let Some(task) = self.tasks.get_mut(&id) {
task.status = Status::Done;
true
} else {
false
}
}
pub fn list_tasks(&self) -> Vec<&Task> {
let mut tasks: Vec<&Task> = self.tasks.values().collect();
tasks.sort_by_key(|t| t.id);
tasks
}
}
}
// ============================================
// Cargo Command Reference (Demonstrated in the comments):
// ============================================
// Common Commands:
// cargo new project_name -- Create a New Project
// cargo build -- Compilation (debug)
// cargo build --release -- Compilation (release optimization)
// cargo run -- Compilation + Run
// cargo check -- Quickly Check for Compilation Errors (No binary files generated)
// cargo test -- Run Test
// cargo test test_name -- Run the specified test
// cargo bench -- Run Performance Benchmarks
// cargo doc --open -- Generate the document and open it
// cargo clippy -- Code lint Inspection
// cargo fmt -- Code Formatting
// cargo add crate_name -- Add Dependencies
// cargo update -- Update Dependencies
// cargo publish -- Post to crates.io
// cargo clean -- Clean up compilation output
//
// Workspace Commands:
// cargo build --workspace -- Compilation workspace All packages in
// cargo test -p task-core -- Test only the specified package
// cargo run -p task-cli -- Run the specified package
fn main() {
use task_core::{Priority, TaskManager};
println!("=== Task Manager (Simulation Workspace Project) ===");
let mut manager = TaskManager::new();
// Create a Task
let id1 = manager.create_task("Study Rust Smart Pointers", Priority::High);
let id2 = manager.create_task("Complete the module system exercises", Priority::Medium);
let id3 = manager.create_task("Restore the Production Environment Bug", Priority::Urgent);
// List all tasks
println!("\n--- All Tasks ---");
for task in manager.list_tasks() {
println!("#{} [{:?}] {} - {:?}", task.id, task.priority, task.title, task.status);
}
// Complete a task
manager.complete_task(id1);
println!("\nDone #{} after:", id1);
for task in manager.list_tasks() {
let status = if task.is_completed() { "Completed" } else { "In progress" };
println!("#{} {} - {}", task.id, task.title, status);
}
// Get a Single Task
if let Some(task) = manager.get_task(id3) {
println!("\nUrgent Task: #{} {} ({:?})", task.id, task.title, task.priority);
}
println!("\n=== End of Presentation ===");
println!("Project Structure: task-core (Library) + task-cli (CLI) + task-web (Web)");
println!("Usage `cargo test -p task-core` Testing the Core Library");
println!("Usage `cargo doc --open` Generate Document");
}
出力:
=== Task Manager (Simulation Workspace Project) ===
--- All Tasks ---
#1 [High] Study Rust Smart Pointers - Todo
#2 [Medium] Complete the module system exercises - Todo
#3 [Urgent] Restore the Production Environment Bug - Todo
Done #1 after:
#1 Study Rust Smart Pointers - Completed
#2 Complete the module system exercises - In progress
#3 Restore the Production Environment Bug - In progress
Urgent Task: #3 Restore the Production Environment Bug (Urgent)
=== End of Presentation ===
Project Structure: task-core (Library) + task-cli (CLI) + task-web (Web)
Usage `cargo test -p task-core` Testing the Core Library
Usage `cargo doc --open` Generate Document
Workspaceは、複数のパッケージからなるプロジェクトを管理するための強力なツールです。
task-coreはコアとなる型とロジック(ライブラリ)を提供し、task-cliはコマンドラインインターフェース(実行ファイル)を提供し、task-webはWeb API(別の実行ファイル)を提供し、cargo build --workspaceはすべてのパッケージを一度にコンパイルします。cargo test -p task-coreは、コアライブラリのみをテストします。
(5) ▶ サンプル:総合演習—モジュール設計のシミュレーション(難易度 ⭐⭐⭐)
// ============================================
// Comprehensive Example: Module Visibility and API Design
// Simulating a Multi-File Project Structure (Actual projects should be broken down into separate files.)
// ============================================
mod math_utils {
pub fn add(a: i32, b: i32) -> i32 { a + b }
pub fn multiply(a: i32, b: i32) -> i32 { a * b }
fn internal_check(val: i32) -> bool { val >= 0 }
pub fn safe_divide(a: i32, b: i32) -> Option<i32> {
if b == 0 { return None; }
if !internal_check(a) || !internal_check(b) { return None; }
Some(a / b)
}
pub mod constants {
pub const PI: f64 = 3.14159265358979;
pub const E: f64 = 2.71828182845905;
pub const MAX_I32: i32 = i32::MAX;
}
}
mod string_utils {
pub fn capitalize(s: &str) -> String {
let mut chars = s.chars();
match chars.next() {
None => String::new(),
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
}
}
pub fn truncate(s: &str, max_len: usize) -> String {
if s.len() <= max_len { s.to_string() }
else { format!("{}...", &s[..max_len.min(s.len())]) }
}
}
mod user {
pub struct User {
pub name: String,
age: u8,
email: String,
}
impl User {
pub fn new(name: &str, age: u8, email: &str) -> Self {
User { name: name.to_string(), age, email: email.to_string() }
}
pub fn age(&self) -> u8 { self.age }
pub fn summary(&self) -> String {
format!("{} ({} years old, {})", self.name, self.age, self.email)
}
}
}
fn main() {
use math_utils::{add, multiply, safe_divide, constants};
use string_utils::{capitalize, truncate};
use user::User;
println!("=== math_utils Module ===");
println!("2 + 3 = {}", add(2, 3));
println!("4 * 5 = {}", multiply(4, 5));
println!("10 / 3 = {:?}", safe_divide(10, 3));
println!("10 / 0 = {:?}", safe_divide(10, 0));
println!("PI = {:.5}, E = {:.5}", constants::PI, constants::E);
println!("\n=== string_utils Module ===");
println!("capitalize: '{}'", capitalize("rust"));
println!("truncate: '{}'", truncate("Hello, World!", 8));
println!("\n=== user Module ===");
let alice = User::new("Alice", 30, "alice@example.com");
println!("{}", alice.summary());
println!("Age: {}", alice.age());
}
出力:
=== math_utils Module ===
2 + 3 = 5
4 * 5 = 20
10 / 3 = Some(3)
10 / 0 = None
PI = 3.14159, E = 2.71828
=== string_utils Module ===
capitalize: 'Rust'
truncate: 'Hello, ...'
=== user Module ===
Alice (30 years old, alice@example.com)
Age: 30
モジュール設計の3つの原則:
pub必要なAPI(addやsafe_divideなど)のみを公開し、内部の詳細(internal_checkなど)は非公開にする; サブモジュール(constantsなど)はpub modを介して公開される。構造体のフィールドには、個別に可視性(privatepub name/age+age()ゲッター)が注釈として付される。
❓ よくある質問
mod と fn の違いは何ですか?ファイルを使って整理しないのはなぜですか?mod はモジュール定義であり、fn は関数定義です。pub(crate) と pub の違いは何ですか?pub(crate) は同じクレート内のコードからのみ参照可能ですが、pub はすべての外部クレートから参照可能です。use super::xxx と use crate::xxx はいつ使用すべきですか?super は親モジュールへのアクセス(相対パス)に使用され、crate はクレートのルートから始まるコンテンツへのアクセス(絶対パス)に使用されます。^1.2.3 はどういう意味ですか?^ は「互換性アップデート」を表しており、このバージョンでは >=1.2.3 および <2.0.0 が利用可能です。lib.rs と main.rs は共存できますか?📖 まとめ
modキーワード定義モジュール。ネスト可能(mod outer { mod inner { ... } })またはファイルから読み込み可能(mod xxx;)pub可視性の制御:デフォルトでは非公開、pub公開、pub(crate)クレート内でのみ可視、pub(super)親モジュールからのみ可視useパスを導入することで呼び出しを簡略化。相対パスと絶対パスの2種類をサポート:super(親モジュール)およびcrate(ルートモジュール)Cargo.tomlセマンティック・バージョニング(SemVer)を使用して依存関係を管理する;[dependencies]と[dev-dependencies]を分離するcargo build/test/doc/benchは Cargo の主要なコマンドであり、cargo clippyおよびcargo fmtはコードの品質を確保するものです- ワークスペース マルチパッケージ管理では、最上位レベルで
Cargo.toml設定が使用され、[workspace]ではすべてのサブパッケージが一覧表示されます
📝 練習問題
- 難易度 ⭐:
mathとgreetingの 2 つのモジュールを含むプログラムを作成してください。mathモジュールにはパブリック関数add(a: i32, b: i32) -> i32が、greetingモジュールにはパブリック関数say_hello(name: &str) -> Stringがあります。main内で、これら2つの関数を呼び出してください。 - 難易度 ⭐⭐:「ライブラリ」モジュールシステムをシミュレートします。
libraryモジュールを作成し、その中にbooksサブモジュール(書籍管理)とmembersサブモジュール(会員管理)を含めます。booksにはadd_bookおよびlist_books関数が、membersにはadd_memberおよびlist_members関数が含まれています。pub(super)およびpub(crate)を使用して、表示設定を適切に制御してください。mainモジュールでは、書籍や会員の追加方法を示しています。 - 難易度 ⭐⭐⭐: Cargo ワークスペースのプロジェクト構造を確認します。
core-lib(addおよびsubtract関数を提供するライブラリ)とcli-app(core-libを使用して計算を行い、結果を出力する実行ファイル)を含むワークスペースプロジェクトをローカルに作成します。Cargo.tomlのワークスペース設定を行い、cargo build --workspaceを使用してコンパイルし、cargo run -p cli-appを使用して実行します。



