2019/12/26

Rustのpubキーワードの公開範囲を知る

pubキーワード

C++やjavaなどではpublicprivateprotectedなどのキーワードを付けることで、公開範囲を決定することができますが、Rustではシンプルにpubキーワードのみとなっています。その代わり、pub(..)といったかたちで範囲を変更することができます。

最初に非公開の構造体の例を挙げます。今回は便宜上同一ファイル内にすべて書いています。モジュールaには、構造体Aがあります。この構造体は見やすくするためにユニット構造体(フィールドなし)にしています。

mod a {
    struct A;
}

fn main() {
    let x = a::A; // ERROR
}
これはpubがついていない構造体なので、モジュールa内でのみ有効なものとなり、当然エラーとなります。
namespace、名前空間、package、blockなど、言語のよって呼び名や仕様は様々ですが、要は使える範囲のことでスコープといい、Rustでも同じようにそういったものがあります。モジュールもその一つです。
公開にしたい場合はpub struct A;としなければなりません。例えばこの構造体がA {x: i32, y: i32}というように、いくつかフィールドを持っているならば、それらについてもpubで公開範囲を指定できます。
では以下の場合はどうでしょうか?

mod a {
    pub(self) struct A;
}

fn main() {
    let x = a::A; // ERROR
}
pubがついていますが、さらに(self)と続いています。
この場合、公開範囲はmod a自身(self)となります。つまりmod aの外には公開していないということになりますので、最初の例の時と同様のエラーとなります。
では以下のような場合はどうなるでしょうか?

mod a {
    pub mod aa {
        pub(super) struct A;
    }
}

fn main() {
    let x = a::aa::A;  // ERROR
}
今回はmod aの中にパブリックなmod aaがあり、その中にpub(super) struct A;とあります。
この場合、mod aa自体は完全に公開となっていますので、どこででも使えますが、構造体Aは公開範囲はsuperとあるので、その親にあたるmod a内となります。したがって、mod aa自体は完全に公開されているものの、肝心の中身はmod aの中でしか使えないということで、この場合も最初の例と同様エラーとなります。
pubキーワードの後には、他にも(crate)(in path)などがあります。pub(in self)pub(self)と等価、pub(in super)pub(super)と等価です。
例えば自作ライブラリの中で、pub(crate)を使用したならば、それはそのライブラリの中でのみ使用され、ライブラリを使う方々には非公開という状態になります。
何かしら大きなアプリケーションやライブラリを作成・公開しようとお考えの場合は結構重要なものかもしれません。