【Rust】がばがばRust独学 - 7. Packages/Crates/Modules
Rustの公式ドキュメントを通して、Rustを独学していく記事になります。(がば要素あり)
今回は、Packages、Crates、Modulesについて学びつつ、気になった点をコード確認した結果を記事にしています。
- versions
$ rustc --version rustc 1.40.0 (73528e339 2019-12-16)
Packages、Crates、Modulesとは?
公式ドキュメント(Managing Growing Projects with Packages, Crates, and Modules - The Rust Programming Language)より
- Packages:Cratesの構築・テスト・共有ができるCargoの機能
- Crates:ライブラリや実行可能ファイルを生成するモジュールツリー
- Modules:Pathsの構成・範囲・プライバシーの制御
- Paths:構造体・関数・モジュールなどのアイテムへの命名方法
Packages and Crates
Cargo.toml
ファイルにより、パッケージを提供可能です。
例えば、下記のように新しい my-project
という名前のPackageを生成した場合、 Cargo.toml
、src/main.rs
が生成されます。
$ cargo new my-project
パッケージは1つ以上のBinary Crateと、0つ以上のLibrary Crateを含むものであり、各rootは以下のファイルにより管理されます。
src/main.rs
:Binary Crate rootsrc/lib.rs
:Library Crate root
Modules and Paths
下記により、新しい restaurant
という名前のライブラリを生成することができます。
$ cargo new --lib restaurant
公式ドキュメント(Defining Modules to Control Scope and Privacy - The Rust Programming Language)より、コードを引用させていただくと、例えば、上記のライブラリの 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() {} } }
下記のようなcrateからのpathにより、ライブラリが利用可能です。
crate └── front_of_house ├── hosting │ ├── add_to_waitlist │ └── seat_at_table └── serving ├── take_order ├── serve_order └── take_payment
全体像
ドキュメントを読み進めていったが、わからん・・・ ということで、demo codeを作成しました。
training-rust/lib.rs at master · KentaHara/training-rust · GitHub を元に各記法について記載します。
各Moduleは mod
により定義します。今回の場合、 TODOリストのCRUD(Deleteは省く)を意識して、 todo_list
のModuleを作成しました。 内容としては、 comment
と description
を扱えるような簡易的なものとなっています。
pub mod todo_list { // ... pub mod comment { // ... } pub mod description { // ... } }
pub
により、対象のModuleをpublicとして扱うことが可能になります。src/main.rc
内で自由に扱いたいため、Moduleは全てpublicにしています。
関数については一部記法の動作確認のために、description内で fn _get(id: u8) -> Option<String>
を記述し、 pub fn get(id: u8) -> Option<String>
からの読み出しをしています。
同一module内で対象の関数を呼び出す場合は、 self::
を利用します。
self::_get(id)
また、特定モジュールから見た親を利用する場合は super
を利用します。今回の場合、comment
から todo_list
の print_message
を comment::create
から呼び出しています。
super::print_message(&message);
src/lib.rs
内でModuleを利用する場合は、下記のように crate::todo_list::comment
や todo_list::comment
により利用することが可能です。
pub fn todo_list_comment_create(message: String) -> Option<u8> { crate::todo_list::comment::create(message) } pub fn todo_list_comment_update(message: String) -> Option<u8> { todo_list::comment::update(Some(1), message) }
crate
を利用することで絶対パスとなり、利用しない場合は相対パスによる呼び出しとなります。
デモコードには記載していませんが、 structやenumについてもModuleによる制御が可能です。
src/main.rs
(training-rust/main.rs at master · KentaHara/training-rust · GitHub)で使用する場合には、下記のように use
により、Moduleを呼び出します。
use pcm::todo_list::comment as ToDoComment; use pcm::todo_list::description::*; use pcm::todo_list_comment_create; use pcm::todo_list_comment_update;
use pcm::todo_list::comment as ToDoComment;
の as
を利用して対象のModuleを別名として利用することが可能です。 as
を利用しないパターン、例えば use pcm::todo_list::comment
ですと、comment::xxx
により、処理で利用できます。
use pcm::todo_list::description::*;
の *
は対象モジュール内の関数等を全て呼び出して利用可能とします。そのため、下記のような後続処理として利用可能です。
update(Some(1), String::from("description message"));
上記の場合は、関数名の衝突がありえます。例えば、 src/main.rs
に対して、下記を追加した場合、main.rs
が優先されます。
fn get(id: u8) -> Option<String> { match id { 1 => Some(String::from("No.1 local Message")), _ => None, } }
また、 src/lib.rs
直下の関数を利用する場合は、 use pcm::todo_list_comment_update;
のように記述することで、利用可能です。
デモコードには記載はしておりませんが、公式ドキュメント(Bringing Paths Into Scope with the use Keyword - The Rust Programming Language)より、公開されているpackagesを利用する場合、 Cargo.toml
に対して下記のように記述することで、利用可能です。
[dependencies] rand = "0.5.5"
最後に
概念はドキュメントから分かるものの、実際の落とし込みは書いてみないとなんとも難しいですね・・・
Moduleを跨いだ場合の使用方法やDIに関しても今後知見を広めていければと考えております。
次は、Collectionsを記載していきます。
教えて、偉い人!
VSCodeで use
にエラーが多発して、ジャンプができないため追っていくのが大変です・・・