1. ホーム
  2. module

[解決済み] モジュールを複数のファイルに分割する

2022-07-07 16:26:44

質問

複数の構造体を含むモジュールを作成したい。 をそれぞれ独自のファイルに格納したい。 を使うことで Math モジュールを例にしています。

Math/
  Vector.rs
  Matrix.rs
  Complex.rs

各構造体は同じモジュールに収めたいので、メインファイルから以下のように使用します。

use Math::Vector;

fn main() {
  // ...
}

しかし、Rustのモジュールシステムは(そもそもちょっとわかりにくいのですが)、これを行うための明白な方法を提供していません。モジュール全体を1つのファイルにまとめることしかできないようです。これは錆びないのでしょうか?そうでないなら、どうすればいいのでしょうか?

どのように解決するのですか?

Rustのモジュールシステムは実は信じられないほど柔軟で、コードがファイルでどのように構成されているかを隠しつつ、好きな種類の構造を公開することができます。

ここでの鍵は pub use を利用することです。これにより、他のモジュールから識別子を再輸出することができます。これにはRustの std::io クレートで、サブモジュールからのいくつかの型は で使用するために再エクスポートされます。 std::io .

Edit (2019-08-25): 答えの以下の部分はかなり前に書かれたものです。このようなモジュール構造を rustc だけでこのようなモジュール構造をセットアップする方法を説明しています。今日では、ほとんどのユースケースでCargoを使用するのが普通でしょう。以下はまだ有効ですが、その一部(例えば #![crate_type = ...] ) は奇妙に見えるかもしれません。これは推奨される解決策ではありません。

あなたの例に合わせるために、このディレクトリ構造で始めることができます。

src/
  lib.rs
  vector.rs
main.rs

ここで、あなたの main.rs :

extern crate math;

use math::vector;

fn main() {
    println!("{:?}", vector::VectorA::new());
    println!("{:?}", vector::VectorB::new());
}

そして、あなたの src/lib.rs :

#[crate_id = "math"];
#[crate_type = "lib"];

pub mod vector; // exports the module defined in vector.rs

そして最後に src/vector.rs :

// exports identifiers from private sub-modules in the current
// module namespace
pub use self::vector_a::VectorA;
pub use self::vector_b::VectorB;

mod vector_b; // private sub-module defined in vector_b.rs

mod vector_a { // private sub-module defined in place
    #[derive(Debug)]
    pub struct VectorA {
        xs: Vec<i64>,
    }

    impl VectorA {
        pub fn new() -> VectorA {
            VectorA { xs: vec![] }
        }
    }
}

そして、ここでマジックが起こります。私たちはサブモジュール math::vector::vector_a というサブモジュールを定義し、特殊なベクトルを実装しています。しかし、あなたのライブラリのクライアントには、このような vector_a サブモジュールがあることは気にしないでください。その代わり、私たちはそれを math::vector モジュールで利用できるようにします。これを行うには pub use self::vector_a::VectorA を再エクスポートします。 vector_a::VectorA の識別子を現在のモジュールに再エクスポートします。

しかし、特別なベクターの実装を別のファイルに置くことができるように、これをどのように行うか質問しました。これは mod vector_b; 行が行うことです。これは、Rust コンパイラに vector_b.rs ファイルを探すように指示します。そして案の定、ここに私たちの src/vector_b.rs ファイルです。

#[derive(Debug)]
pub struct VectorB {
    xs: Vec<i64>,
}

impl VectorB {
    pub fn new() -> VectorB {
        VectorB { xs: vec![] }
    }
}

クライアントの立場からすると、このように VectorAVectorB が2つの異なるファイルの2つの異なるモジュールで定義されていることは、完全に不透明です。

もし、同じディレクトリにある main.rs で実行できるはずです。

rustc src/lib.rs
rustc -L . main.rs
./main

一般に "クレートとモジュール" の章を参照してください。 の章はかなり良いです。たくさんの例があります。

最後に、Rustコンパイラはサブディレクトリの中も自動で探してくれます。 例えば、上記のコードはこのディレクトリ構造で変更なく動作します。

src/
  lib.rs
  vector/
      mod.rs
      vector_b.rs
main.rs

コンパイルと実行のコマンドも同じです。