Rustでは、可視性修飾子はモジュールの要素(構造体、関数、定数など)へのアクセスを管理します。デフォルトでは、モジュール内で宣言されたすべてのものはプライベートです(そのモジュール内でのみアクセス可能)。特別な修飾子があります。
pub: 要素を公開にします(外部モジュールから見える)。pub(crate): 可視性は現在のクレート(パッケージ)に制限されます。pub(super): 可視性は親モジュールに制限されます。pub(in path): 可視性は指定されたパスに制限されます。例:
mod foo { pub struct Bar { pub x: i32, // フィールドはどこでも見える y: i32, // フィールドはプライベート } pub(crate) fn crate_fn() {} pub(super) fn super_fn() {} fn private_fn() {} }
C++やJavaなどとの主な違いは、protectedのための独立したレベルが存在せず、アクセスがモジュール/パスのレベルで厳密に管理されることです。
質問: 構造体が pub struct Foo として宣言された場合、そのプライベートフィールドは同じプロジェクトの別のモジュールでアクセス可能か?
よくある回答: はい、構造体は公開されているので。
正しい回答: いいえ、構造体自体(Foo)のみが公開され、そのフィールドはフィールドも pub 修飾子で宣言されていない限りアクセスできません。pub なしのフィールドはプライベートのままで、構造体が公開されていてもアクセスできません。
例:
mod foo { pub struct Bar { pub x: i32, y: i32, } } fn main() { let bar = foo::Bar { x: 1, y: 2 }; // エラー: フィールド `y` はアクセスできません }
物語
大規模なプロジェクトで構造体をpubで公開したが、フィールドはデフォルトでプライベートにした。他のモジュールは構造体のインスタンスを直接作成できず、唯一の解決策は追加のコンストラクタを書くか、必要なフィールドをpubとして宣言することだった。これによりAPIの拒否が発生し、最終的な改良が必要になった。
物語
ある開発者がライブラリで関数に pub(crate) のみを使用し、このライブラリを使用するバイナリプロジェクトから呼び出すことができると考えていた。しかし、そのような関数は外部のバイナリクレートでアクセスできなくなり、統合時に問題が発生した。
物語
APIサーバーのプラグインの1つで構造体に pub(super) を使用していたが、後に他のモジュールからのアクセスが必要になることがあった。可視性の設定のため、一部のモジュールを根本的に書き直さざるを得なくなり、エンカプセル化を損なうことなく必要な可視性を確保する必要があった。