この辺、細かい説明がなくてよくわからんかった。ので、使ってみた。
成果物
参照
- https://doc.rust-jp.rs/book/second-edition/ch07-01-mod-and-the-filesystem.html
- https://doc.rust-jp.rs/book/second-edition/ch07-02-controlling-visibility-with-pub.html
上記を学習しているとき、当然のようにmod ... ;
, use ... ;
, extern crate ... ;
の構文が出てきた。でも、こいつらの動作がよくわからない。そのままmod
やpub
の説明されても納得しがたい。そこでそれらについて動作確認してルールを確認してみた。
modの参照方法
別ファイルに定義されたモジュールを参照する方法は3つある。
extern crate クレート名;
mod 子モジュール名;
use モジュール名::要素名;
参照元と被参照の親子関係などによって、どれを使うべきかが決まる。3つの内、下にあるものほど使える場所が多い。
extern crate クレート名;
main.rs
エントリポイントでlib.rs
をロードするときに使える。
cargo new my_crate --lib cargo test
- my_crate/
- src/
- main.rs
- lib.rs
- my_mod_1/
- mod.rs
- src/
my_crate/src/main.rs
extern crate my_crate; // 同ディレクトリの`lib.rs`を読込 fn main() { assert_eq!(extern_crate_0::my_mod_1::public(), String::from("my_mod_1::public()")); // assert_eq!(extern_crate_0::my_mod_1::private(), String::from("my_mod_1::private()")); // error[E0603]: function `private` is private }
extern crate
はlib.rs
では使えなかった。
my_crate/src/lib.rs
//extern crate extern_crate_0; // error[E0463]: can't find crate for `extern_crate_0` pub mod my_mod_1; #[cfg(test)] mod tests { // extern crate my_crate; // error[E0463]: can't find crate for `my_crate` // extern crate super::my_crate; // error: expected identifier, found keyword `super` // use super::my_mod_1; // error[E0432]: unresolved import `super::my_mod_1` // use my_mod_1; // error[E0432]: unresolved import `my_mod_1` // mod my_mod_1; // error[E0583]: file not found for module `my_mod_1` // mod super::my_mod_1; // error: expected identifier, found keyword `super` use super::*; #[test] fn test_my_mod_1_public() { assert_eq!(my_mod_1::public(), String::from("my_mod_1::public()")); // error[E0433]: failed to resolve: use of undeclared type or module `my_crate` } #[test] fn test_my_mod_1_private() { // assert_eq!(my_mod_1::private(), String::from("my_mod_1::private()")); // error[E0603]: function `private` is private } }
extern crate
はmod.rs
では使えなかった。
my_crate/src/my_mod_1/mod.rs
//extern crate my_crate; // error[E0463]: can't find crate for `my_crate` pub fn public() -> String { String::from("my_mod_1::public()") } fn private() -> String { String::from("my_mod_1::private()") }
mod 子モジュール名;
外部ファイル化された子モジュールを宣言するための構文。
外部ファイル化されたモジュールの場合、pub
であるか否かの情報がない。よって、それを直上の親モジュールが指定してやる。そのための構文。
宣言
pub mod 子モジュール名;
とすると、これを宣言したモジュールを介して参照可(先祖・子孫に関係なく)mod 子モジュール名;
とすると、これを宣言したモジュールを介して参照不可。ただし子孫モジュール配下からはsuper::
を介して参照可
制約
main.rs
,lib.rs
,mod.rs
等で使える(主にlib.rs
,mod.rs
で使うはず)- 外部ファイル化されたモジュールのみ対象(ファイル内なら
mod my_mod_1 { ... }
のように実装される。それの代わり) - 直下の子のみ
mod super::my_mod_1;
のように先祖は参照不可(error: expected identifier, found keywordsuper
)mod my_mod_1::my_mod_2;
のように直下の子より深い子孫は参照不可(error: expected one of;
or{
, found::
)
例
別ファイルにある子モジュールを参照
lib.rs
から直下モジュールmy_mod_1/mod.rs
を参照する。
src/lib.rs
mod my_mod_1; fn a() { my_mod_1::public(); // my_mod_1::private(); // error[E0603]: function `private` is private }
src/my_mod_1/mod.rs
pub fn public() -> String { String::from("my_mod_1::public()") } fn private() -> String { String::from("my_mod_1::private()") }
同一ファイル内にある子モジュールを参照
src/my_mod_1/mod.rs
fn a() { sub::my_fn(); } mod sub { fn my_fn() [ println!("hello"); } }
super
親を参照する。private要素も参照できる。親モジュール側でmod 子モジュール;
とすると親子関係が定義され、子モジュール側でsuper
が使えるようになる。
なお、super::super::
のように複数回参照すれば先祖も辿れる。
同一ファイル内にある子モジュールtests
から親を参照
親の参照にはsuper
を使う。
src/my_mod_1/mod.rs
pub fn public() -> String { String::from("my_mod_1::public()") } pub fn private() -> String { String::from("my_mod_1::private()") } mod tests { fn test() [ super::public(); } }
- 親を
use
する必要はない mod 子モジュール;
は子モジュールのみ対象なので、子が親を参照するときには使えないextern crate 自クレート名;
はmain.rsでしか使えない
別ファイルにある子モジュールから親を参照
src/lib.rs
mod my_mod_1; fn parent() { println!("hello"); }
src/my_mod_1/mod.rs
pub fn pub_call_parent() { super::parent(); }
use
use
は、別ファイルで定義されたpub
な要素を参照するときに使う。特に、extern crate クレート名
, mod 子モジュール名;
では参照できない場合に。
つまり、main.rs
ファイル以外で、直下の子モジュールでない要素を参照したいとき、use
を使う。たとえば親、兄弟、先祖、子孫、兄弟の子孫や先祖。
- 親がもつ要素:
use super::要素名;
- 子がもつ要素:
use 子モジュール名::要素名;
- 先祖がもつ要素:
use super::super::要素名;
- 子孫がもつ要素:
use 子モジュール名::孫モジュール名::要素名;
- 兄弟がもつ要素:
use super::兄弟モジュール名::要素名;
- 兄弟の先祖がもつ要素:
use ::兄弟の先祖::兄弟の先祖:: ... ::要素名;
- 兄弟の子孫がもつ要素:
use ::兄弟の先祖:: ... ::兄弟の子孫::要素名;
use 要素名;
use
する要素はpub
である必要がある。なお、要素はmod
, fn
, enum
, struct
, trait
と思われる。
要素のパスは、これを宣言したモジュールを基準とする。つまり子要素を対象とする。
use ::要素名;
先頭に::
があるとルートからのパスとなる。
use モジュール名::要素名;
これを宣言したモジュールを基準としたパス。つまり子モジュールの要素を対象とする。
use super::要素名
親の要素もuse
できる。なお、先祖の場合はsuper::super::
のように辿る数だけsuper
を付与すればいい。
use モジュール名::*
*
とすれば、指定したモジュール内で定義されている要素すべてを、そのモジュールの接頭辞なしで参照できるようになる。名前重複しやすくなるため注意。
他にもsuper::*
など指定方法はさまざま。
まとめ
参照方法 | 呼出元 | 呼出対象 | 概要 |
---|---|---|---|
extern crate クレート名; |
main.rs |
lib.rs やCargo.toml で指定した外部クレート |
|
mod モジュール名; |
main.rs , lib.rs , mod.rs |
外部ファイル化した子モジュール | |
use 要素名; |
main.rs , lib.rs , mod.rs |
外部ファイル化したpub な要素mod ,fn ,struct ,enum ,trait (先頭:: で絶対パス、それ以外で相対パス。末尾::* で全要素を接頭辞なし読込) |
外部ファイルの要素を参照するときのまとめ。誰が、誰を参照するとき、どう宣言し、どう参照するかの一覧。
誰が | 誰を | どう宣言 | どう参照 |
---|---|---|---|
main.rs(ファイル最上) | Cargo.tomlで指定した外部クレート | extern crate 外部クレート名; |
外部クレート名::要素名; |
main.rs(ファイル最上) | 同一クレート内の lib.rs | extern crate 自クレート名; |
自クレート名::要素名; |
モジュール(ファイル最上) | 直下の子モジュール | mod 子モジュール; |
子モジュール::要素名; |
モジュール, fn | 指定パスにある指定した要素 | use ::要素; , use 親::子; , use 要素::* , use super::要素; |
::要素名::子要素名; , 親::子 , 要素名 , super::要素 , super::super::要素 |
主な用途
mod 子モジュール名
, use 要素名;
, extern crate クレート名;
は外部ファイルの要素を参照するときに使う。(C/C++でいう#include
的)
extern crate クレート名
main.rsでのみ使う。
- 内部lib.rs読込: main.rsで
extern crate 自クレート名;
とすると自クレート内のlib.rsを読み込む - 外部クレート読込: main.rsで
extern crate 外部クレート名;
とすると外部クレートを読み込む(外部クレートはCargo.tomlで読込を指示する)
クレート名::要素名
で参照できるようになる。
mod 子モジュール名;
主にlib.rs, mod.rsで使う。直下の外部ファイル化した子モジュールを探して読み込む。pub
か否か指定する。
子モジュール名::要素名
で参照できるようになる。
use 要素名;
main.rs, lib.rs, mod.rs, いずれでも使用可。
外部ファイル化したモジュールやその他の要素を読み込む。
参照する要素は以下のようにパス指定する。
use ::要素名
でルートsrc/
配下からの参照パス指定をするuse 要素名
でそのuse
宣言したモジュールを起点とした相対パスとなる
なお、複数の要素をすべて読込たいときは::*
が使える。
use 要素名::*
で要素名
配下にあるすべての子要素は要素名::
の接頭辞なしに参照できる
ただし、接頭辞がなくなるため、名前重複しやすくなるので注意。
前回まで
- Rustを学んでみたい(プログラミング言語)
- Rustの環境構築
- RustでHelloWorld
- Rustの和訳ドキュメント
- Cargoでプロジェクト作成・ビルド・実行
- クレートとは?
- Rustで関数を使ってみる
- Rustでモジュールを使ってみる
- Rustで乱数を生成する(rand)
- Rustで標準入力する(std::io::stdin().read_line())
- RustでMatch判定する(match)
- Rustでprintとread_lineを1行にする方法
- Rustで数当てゲーム
- クレート名にドット.が使えない
- Rustの変数と可変性(let, mut) error[E0384]: cannot assign twice to immutable variable
x
- Rustのimmutable束縛とconst定数の違い
- RustのREPL、evcxrのインストールに失敗した
- Rustでコンパイルするときの変数未使用warningを消す
- Rustの変数(再代入、再宣言(シャドーイング))
- Rustのシャドーイングについて
- イミュータブルについて(副作用)
- Rustの定数(const)
- Rustのデータ型(数値)
- Rustのデータ型(論理)
- Rustのデータ型(文字)
- Rustのデータ型(タプル)
- Rustのデータ型(配列)
- Rustの関数
- Rustのif式
- Rustのくりかえし文(loop)
- Rustのくりかえし文(while)
- Rustのくりかえし文(for)
- Rustの所有権(ムーブ)
- Rustの所有権(関数)
- Rustの所有権(スライス)
- Rustの構造体(定義とインスタンス化)
- Rustの構造体(プログラム例)
- Rustの構造体(メソッド)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustの列挙型(enum)
- Rustのmatch(制御フロー演算子)
- RustでNULLを扱う(Option, Some, None)
- NULL参照は10億ドルの失敗だった
- Rustの列挙型に独自表示を実装する(E0277 対策 std::fmt::Display 実装)
- RustのIfLet(matchの糖衣構文)
- Rustのプロジェクト構造
- Rustのcargoでライブラリ&テスト(単体、結合)
- Rustのモジュール(mod)
- Rustのモジュール(pub)