時折Rust言語を使ってみては、慣れぬRustのお作法に行く手を阻まれます。今回は、関数やらモジュールやらを別ファイル(ついでに別階層)にして取り込む件。Cのようにヘッダファイルを作ったり、Makefile書いたりする必要ないですが、初心者にはあまり親切ではない気がします。やれば出来る?ホントか。
※「やっつけな日常」投稿順 indexはこちら
今回は真っ先に以下の「偉大なコメント」を引用させていただきたいと思います。これひとつでスッキリ? いつもお世話になっております「Rust By Example 日本語版」の以下のページからの引用でございます。
“mod my;” という短い1行に対するコメントなんであります。
なんだ、そういうことかい。
「パッケージとクレート」読んでました
最初、パッケージとクレートについて調べ始めて沼にハマりました。Rustには素晴らしいモジュール管理システムが備わってます。パッケージとクレートについても理解しないとイケないのだと思いますが、今回やりたかったのは、「main.rs内で定義している関数などを別ファイルに追い出したい」ついでによくやる風に「ローカル・ライブラリ的なフォルダを掘って別階層にまとめたい」という程度の事なんであります。とりあえず戸惑った第1歩だけ書き留めておきますが、ファイルを分けるだけならココは飛ばして大丈夫です。
Rustのプロジェクトを作る場合、Cargoに以下のようにお願いして xxx などというプロジェクトホルダを作ると思います。
cargo new xxx
上記の場合、「バイナリ」パッケージで、srcサブフォルダの中に main.rs の雛形が用意されてます。
それに対してライブラリのプロジェクトを作るときはオプション –lib つけるとsrcサブフォルダの中に lib.rs の雛形が用意されてます。
cargo new yyy --lib
そして上記の2つは両立しない、ようです。ライブラリ・プロジェクトの作り方を調べても的外れだったみたいです。
Rustにはクレートという概念があり、クレートルートというものを開始点に組織化されてます。そこで
-
- クレートにはバイナリとライブラリの種別がある
- パッケージは最低一つのクレートを持たねばならない
- パッケージが持てるライブラリ・クレートは0または1個
- パッケージが持てるバイナリ・クレートの数に制限はない
なんやら複雑な。。。そしてこの辺を読んでいても現状目的とする方向へは進まず、深みにズブズブとクレートなるものにハマって行きます。その辺はまた今度。
まずは単一ファイル内でのモジュール内関数の呼び出しから
まずは、main.rs内で、簡単なモジュールを定義してその中の関数を呼んでみるところから。こんな感じ。
普通に cargo run などとすれば、ビルドされて走ります。実行後のプロジェクト・フォルダのツリー(一部)は以下のようです。
同一階層でファイルを分けてみる
同一階層でファイルを2つに分割してみました。ソースの階層構造が以下に。
同一ファイルの時には、sub1をmod{ } で囲っていたのに削除してます。これは main.rs内で、mod trial; と宣言したときに既に mod にくるまれているためです。trial.rsファイル内に modを書くと、二重になってしまい、::trial::trial::sub1みたいな長いパスで呼ばねばならないなります。
階層構造にする
ここから階層構造にするのは簡単です。
-
- trial.rs をmod.rsとリネーム
- trialという名のサブフォルダを掘って
- mod.rs をtrialサブフォルダにMOVE
mod.rsとか「マジックな」ファイル名を知っていたら簡単でしたな。
しかしこれだけではツマラナイので、さらにネストしたモジュール・ファイルを置いてこれも参照できるようにしてみました。階層構造が以下に。
追加した nested2.rs の中身が以下です。超シンプルなモジュール。モジュールも関数も皆パブリック。
そして mod.rs 内に以下一行を付け加えました。
pub mod nested2;
すると main.rs からは以下のように trial経由のnested2経由のtrial2モジュール内のsub2という長いお名前でアクセスできました。
trial::nested2::trial2::sub2();
全部合わせた実行結果が以下に。
たったこんだけ、でもま、会得したような気がする。気のせいじゃないのか自分?