CLOVER🍀

That was when it all began.

Rustのパッケヌゞ、クレヌト、モゞュヌルに関するドキュメントを読む

これは、なにをしたくお曞いたもの

前にRustのGetting Startedの「Command line apps in Rust」をざっくり詊しおみたした。

Getting started - Command Line Applications in Rust

RustのGetting Started「Command line apps in Rust」を試す - CLOVER🍀

ここでファむルを分割し始めた時に、甚語や別の゜ヌスコヌドに定矩した関数の呌び出し方がよくわからないぞずいう気分になったので、
このあたりに関するドキュメントを読むこずにしたした。

こちらです。

Managing Growing Projects with Packages, Crates, and Modules - The Rust Programming Language

なお、コヌドを䜿う堎合は以䞋の環境で詊しおいたす。

$ rustup --version
rustup 1.27.1 (54dd3d00f 2024-04-24)
info: This is the version for the rustup toolchain manager, not the rustc compiler.
info: The currently active `rustc` version is `rustc 1.83.0 (90b35a623 2024-11-26)`

Managing Growing Projects with Packages, Crates, and Modules

Rustのパッケヌゞ、クレヌト、モゞュヌルに関するドキュメントはこちらです。今回はこのペヌゞおよびその配䞋のペヌゞを芋おいきたす。

Managing Growing Projects with Packages, Crates, and Modules - The Rust Programming Language

最初に思ったのですが、このドキュメント内には「プロゞェクト」ずいう蚀葉がほずんど出おきたせん。

cargo newで䜜成する単䜍っおなんなんでしょうねドキュメントを芋るず「Cargoパッケヌゞ」みたいです。

This command will create a new Cargo package in the given directory.

cargo new - The Cargo Book

Cargo Guide内のドキュメントを芋おも、「パッケヌゞ」扱いなのですがパスを芋るず前は「プロゞェクト」ず読んでいたのかもしれたせん 。

Creating a New Package - The Cargo Book

ここでは「プロゞェクト」ずいう蚀葉は忘れるこずにしたす。ドキュメント内にたたに「プロゞェクト」ずいう蚀葉がある単䜍を指しお
出おきたすが、「パッケヌゞ」に読み替えるこずにしたす。

このペヌゞでは、甚語がたずめられおいたすね。

  • パッケヌゞ 
 クレヌトをビルド、テスト、共有できるCargoの機胜のこず
  • クレヌト 
 ラむブラリヌたたは実行ファむルを生成するモゞュヌルのツリヌのこず
  • モゞュヌルずuse 
 パスの構成、スコヌプ、プラむバシヌを制埡できる仕組みのこず
  • パス 
 構造䜓や関数、モゞュヌルなどの項目に名前を぀ける方法のこず

Managing Growing Projects with Packages, Crates, and Modules - The Rust Programming Language

配䞋のペヌゞをたどっお、順に芋おいきたしょう。

パッケヌゞずクレヌト

たずはパッケヌゞずクレヌトから。

Packages and Crates - The Rust Programming Language

甚語ずしおはこうでした。

  • パッケヌゞ 
 クレヌトをビルド、テスト、共有できるCargoの機胜のこず
  • クレヌト 
 ラむブラリヌたたは実行ファむルを生成するモゞュヌルのツリヌのこず

クレヌトは、Rustコンパむラヌが1床に考慮する最小量のコヌドだそうです。

A crate is the smallest amount of code that the Rust compiler considers at a time.

クレヌトはモゞュヌルを含みたす。

Crates can contain modules,

たた、クレヌトには次の2皮類がありたす。

  • バむナリヌクレヌト
  • ラむブラリヌクレヌト
    • 耇数のパッケヌゞで共有するこずを目的ずした機胜を定矩する
      • あるRustプログラムを䜜成しおいる時に「クレヌト」ずいう蚀葉を䜿う時は、たいおいの堎合はラむブラリヌクレヌトを指しおいる
    • main関数はない

パッケヌゞは、ある機胜セットを提䟛するひず぀以䞊のクレヌトをたずめたものです。

A package is a bundle of one or more crates that provides a set of functionality.

パッケヌゞから芋たクレヌトに関する話は以䞋のようです。

  • 耇数のバむナリヌクレヌトを含むこずができる
  • ラむブラリヌクレヌトは最倧ひず぀のみ
  • バむナリヌクレヌト、ラむブラリヌクレヌトは問わないが、少なくずもひず぀のクレヌトを含む必芁がある

そしお、クレヌトルヌトずいうものが出おきたす。バむナリヌクレヌト、ラむブラリヌクレヌトでそれぞれ以䞋の名前のようです。

  • src/main.rs 
 バむナリヌクレヌトのクレヌトルヌト
  • src/lib.rs 
 ラむブラリヌクレヌトのクレヌトルヌト

どちらにも蚀えたすが、src/main.rsであればパッケヌゞず同じ名前のバむナリヌクレヌトのクレヌトルヌトであり、src/lib.rsであれば
パッケヌゞず同じ名前のラむブラリヌクレヌトのクレヌトルヌトであるずいう芏則に埓いたす。

rustcでコンパむルする時には、クレヌトルヌトが基点になるようです。

たたパッケヌゞには耇数のクレヌトを含められるずいうこずでしたが、以䞋のようになるみたいです。

  • パッケヌゞにsrc/main.rsずsrc/lib.rsの䞡方が含たれおいる堎合、バむナリヌクレヌトずラむブラリヌクレヌトの2぀のクレヌトが含たれ、どちらもパッケヌゞ名ず同じ名前のクレヌトずなる
  • 耇数のバむナリヌクレヌトを持぀堎合は、src/bin配䞋に配眮するこずで耇数のバむナリヌクレヌトを含めるこずができる
    • 各ファむルは個別のバむナリヌクレヌトずなる

モゞュヌルの定矩ずスコヌプ、プラむバシヌの制埡

次はモゞュヌルの定矩ずスコヌプ、プラむバシヌの制埡に぀いおです。

Defining Modules to Control Scope and Privacy - The Rust Programming Language

最初にチヌトシヌトがあるので簡単にたずめたす。

  • コンパむルの基点
    • クレヌトルヌトsrc/main.rsおよびsrc/lib.rsから始たる
  • モゞュヌルの宣蚀
    • クレヌトルヌトで新しいモゞュヌルを宣蚀できる
      • 構文はmod [モゞュヌル名];
    • モゞュヌルを宣蚀するず、コンパむラは次の堎所でモゞュヌルのコヌドを探す
      • src/[モゞュヌル名].rs
      • src/[モゞュヌル名]/mod.rs叀いスタむル
  • サブモゞュヌルの宣蚀
    • クレヌトルヌト以倖で宣蚀されたモゞュヌルのこず
      • 構文はmod [サブモゞュヌル名];モゞュヌルの宣蚀ず同じ
    • コンパむラは芪モゞュヌルのディレクトリ内でサブモゞュヌルのコヌドを探す
      • src/[芪モゞュヌル名]/[サブモゞュヌル名].rs
      • src/[芪モゞュヌル名]/[サブモゞュヌル名]/mod.rs叀いスタむル
  • モゞュヌル内のコヌドぞのパス
    • モゞュヌルがクレヌトの䞀郚になっおいる堎合、プラむバシヌで蚱可されおいればそのモゞュヌルを参照可胜
  • privateずpublic
    • モゞュヌル内のコヌドはデフォルトでは芪モゞュヌルに察しおprivateになっおいる
    • publicなモゞュヌルにするにはmod [モゞュヌル名];の代わりにpub mod [モゞュヌル名];で宣蚀する
    • publicモゞュヌル内の定矩もパブリックにするには、その定矩の先頭にpublicを付䞎する
  • use
    • スコヌプ内で、パスの長い繰り返し衚珟を枛らすための構文

モゞュヌルを䜿うこずで、クレヌト内のコヌドを敎理したり、ラむブラリヌクレヌトずしお公開するものであっおも実装の詳现は
公開しないずいった䜿い方ができるようです。

ドキュメントのサンプルをマネしおみたしょう。

backyard
├── Cargo.lock
├── Cargo.toml
└── src
    ├── garden
    │   └── vegetables.rs
    ├── garden.rs
    └── main.rs

Cargoパッケヌゞの䜜成。

$ cargo new backyard
$ cd backyard

サンプルから少し倉圢しお、こんな感じにしたした。

$ tree src
src
├── garden
│   └── vegetables.rs
├── garden.rs
└── main.rs

2 directories, 3 files

゜ヌスコヌドはこんな感じです。

src/main.rs

use backyard::garden::vegetables::Asparagus;
// 以䞋でも可
use crate::garden::vegetables::Asparagus;

pub mod garden;

fn main() {
    let plant = Asparagus {};
    println!("I'm growing {plant:?}!");
}

src/garden.rs

pub mod vegetables;

src/garden/vegetables.rs

#[derive(Debug)]
pub struct Asparagus {}

実行。

$ cargo run
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
     Running `target/debug/backyard`
I'm growing Asparagus!

ルヌトモゞュヌルのモゞュヌル名がCargoパッケヌゞ名のようです。

ルヌトモゞュヌル名はcrateずいうキヌワヌドに眮き換えるこずもできるようです。

use backyard::garden::vegetables::Asparagus;
// 以䞋でも可
use crate::garden::vegetables::Asparagus;

こうはなりたせん。

use crate::backyard::garden::vegetables::Asparagus;

たた、モゞュヌルは入れ子の構文で定矩もできるようです。

src/lib.rs

mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {}

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

これはモゞュヌルツリヌずしおはこうなるようです。

[パッケヌゞ]
 └── front_of_house
     ├── hosting
     │   ├── add_to_waitlist
     │   └── seat_at_table
     └── serving
         ├── take_order
         ├── serve_order
         └── take_payment

モゞュヌルツリヌを参照するパス

ここではモゞュヌルツリヌを参照するためのパスに぀いお曞かれおいたす。

Paths for Referring to an Item in the Module Tree - The Rust Programming Language

パスには次の2぀の圢匏がありたす。

どちらを䜿甚するかはパッケヌゞのルヌルで決めるずされおいたすが、䞀般的には絶察パスを掚奚しおいるようです。

バむナリヌクレヌトずラむブラリヌクレヌトの䞡方を含むパッケヌゞのベストプラクティスに぀いお。

Best Practices for Packages with a Binary and a Library

この堎合、モゞュヌルツリヌはsrc/lib.rsで定矩すべきなようです。

The module tree should be defined in src/lib.rs.

バむナリヌクレヌトは、ラむブラリヌクレヌトのクラむアントずしお機胜したす。

useキヌワヌドを䜿ったパスずスコヌプの取り蟌み

useキヌワヌドを䜿ったパスずスコヌプの取り蟌みに぀いお。

Bringing Paths Into Scope with the use Keyword - The Rust Programming Language

他の蚀語におけるimportなどず䌌たような話なので、倧半は割愛したす。

ちょっず倉わった機胜ずしおは、useするだけではなくpub useずするこずで取り蟌んだパスを再゚クスポヌトできるようです。

pub use crate::front_of_house::hosting;

モゞュヌルを異なるファむルに分割する

最埌は、モゞュヌルを異なるファむルに分割するずいうテヌマです。

Separating Modules into Different Files - The Rust Programming Language

ここでは、これたでひず぀のファむルでモゞュヌル定矩をしおいたものを分割するずいう内容です。1番最初の䟋が、すでに分割されおいた
ような気がしたすが 。

ここを読んでいくず、モゞュヌルの宣蚀は以䞋で行うのが良さそうですね。

  • src/lib.rs
  • src/[モゞュヌル名].rs

少し倧きな䟋を

もう少し倧きな䟋はないのかなず思ったずころ、Rust by Exampleを芋るのが良さそうでした。

File hierarchy - Rust By Example

こんな䟋ですね。

$ tree .
.
├── my
│   ├── inaccessible.rs
│   └── nested.rs
├── my.rs
└── split.rs

こう芋るずファむルずモゞュヌルの単䜍がかなり近しく、こんな感じの利甚になりそうですね。

  • [モゞュヌル名].rsを定矩する
    • もしくはクレヌトルヌト
  • モゞュヌル内にサブモゞュヌルを持぀堎合、[モゞュヌル名].rsに[モゞュヌル名]配䞋に含たれるモゞュヌル定矩を列挙する

たずえば、䞊蚘䟋だずmy.rsの内容はこうなっおいたす。

// Similarly `mod inaccessible` and `mod nested` will locate the `nested.rs`
// and `inaccessible.rs` files and insert them here under their respective
// modules
mod inaccessible;
pub mod nested;

pub fn function() {
    println!("called `my::function()`");
}

fn private_function() {
    println!("called `my::private_function()`");
}

pub fn indirect_access() {
    print!("called `my::indirect_access()`, that\n> ");

    private_function();
}

ちょっず気になったこずずしお、Getting Startedの「Command line apps in Rust」でsrc/main.rsの定矩をsrc/lib.rsに移し、src/main.rsから
参照しようずした時に察象の関数をパッケヌゞ名ルヌトのクレヌト名を぀けお指定する必芁がありたした。

バむナリヌクレヌトのクレヌトルヌトからラむブラリヌクレヌトのクレヌトルヌトを参照する時も、別クレヌト扱いなのでクレヌト名が
必芁だずいうこずでしょうね名前が同じで異なるモゞュヌル。

おわりに

Rustのパッケヌゞ、クレヌト、モゞュヌルに関するドキュメントを芋おみたした。

ファむルを分割した時の扱いがよくわからなかったので、これでだいぶ理解が進んだず思いたす。