web-dev-qa-db-ja.com

Rustアイテムをクレート内で公開し、その外でプライベートにする方法は?

たくさんのコードが入った木箱があるので、それを複数のファイル/モジュールに分割しました。ただし、いくつかのモジュールには、さまざまなモジュールに公開する必要がある内部の安全でないもの(生のポインターなど)がありますが、クレートのユーザーに公開したくないです。どうやってやるの?

私が考えることができる唯一の方法は、実際に私のクレートを1つの大きなモジュールにすることですが、それから このソリューション which以外の異なるファイルに分割する方法はありません少しハックが多いようです。

通常、Rust docsの簡単な例では十分に説明されていない現実世界の問題に出くわすと、人気のある現実世界の木枠をコピーするだけです。たとえば、 git2-rs 、しかしそれは生のポインタを含むすべてを事実上公開するように思えます。

24
Timmmm

item をライブラリクレートからエクスポートするには、everyコンポーネントがパブリックである少なくとも1つのパスが必要です。これは、クレート内でアイテムを公開する必要がありますが、クレートからエクスポートせずに(C#の用語を模倣するためにこれを「内部」と呼びます)、クレートルートの下のプライベートモジュールに置くだけです。 。

ただし、その解決策は非常に限定的です。エクスポートされた関数および内部関数を備えたモジュールが必要な場合はどうなりますか?一部の関数をエクスポートするには、モジュールをパブリックにする必要があります。つまり、そのモジュール内のすべてのパブリックアイテムもエクスポートされます。

Rust 1.18 なので、この種のシナリオに適応したソリューションがあります: pub(restricted) 。この機能を使用すると、アイテムの「公開方法」を指定できます。構文は非常に柔軟です(クレート全体ではなく特定のモジュールツリーからアイテムを表示できます)が、シンプルに保ちたい場合は、pub(crate)を使用すると、クレート内のどこからでもアイテムにアクセスできます。ただし、他のクレートにはありません(C#のinternalと同等)。

たとえば、utilがエクスポートされるモジュールfooが必要な場合(mycrate::util::foo)、barは内部、bazはモジュール専用です。コードは次のようになります。

pub mod util {
    pub fn foo() {
        unimplemented!()
    }

    pub(crate) fn bar() {
        unimplemented!()
    }

    fn baz() {
        unimplemented!()
    }
}

1.18より前のRustにこだわっている場合は、回避策がありますが、少し不格好です。すべてのアイテムをプライベートモジュールで定義し、公開したいものだけを再エクスポートします(pub useonly再エクスポートを含むパブリックモジュール内。上記の例は次のようになります。

pub mod util {
    pub use util_impl::foo;
}

mod util_impl {
    pub fn foo() {
        unimplemented!()
    }

    pub fn bar() {
        unimplemented!()
    }

    fn baz() {
        unimplemented!()
    }
}

これは読みやすく、理解しにくいだけでなく、pubを使用できるすべての状況をカバーしているわけではありません。たとえば、エクスポートされた構造体の一部のフィールドを、エクスポートせずに、同じクレート内の他のモジュールでアクセス可能にする方法を教えてください。唯一のオプションは、パブリックフィールドを持つ構造体を型とする単一のプライベートフィールドを持つラッパーを公開することです。他のクレートからすべてのフィールドを非表示にする場合は正常に機能しますが、一部のフィールドを公開して他のフィールドを同じ構造内に作成する場合は問題ありません。

40
Francis Gagné