問題の歴史:
C++やJavaのような言語では、アクセス修飾子(public、private、protected)がクラスのメンバーの可視性を確保しますが、かなり柔軟であり、APIの誤った使用を防ぐことはあまりありません。Rustでは、初期のバージョンからアクセス制御のシステムが厳格かつ明示的なモジュールベースにされており、内部の詳細が外部に漏れるのを制限しています。
問題:
構造体は外部コードから部分的に隠す必要があることがよくあります。例えば、フィールドはプライベートであり、外部にはメソッドだけを公開します。アクセスを制限しないと、構造体の不変条件が意図せずに壊れる可能性があります(例えば、内部のVecを直接公開すること)。構造体を無思慮に公開すると、APIが脆弱になります。
解決策:
Rustでは、すべてがデフォルトでプライベートです。キーワードpubは明示的なエクスポートに使用されます。構造体は個別に可視化することができ、フィールドは隠されます。メソッドは個別にpubまたはプライベートとして宣言されます。さらに、pub(crate)やpub(super)のような非標準の形は、アクセスレベルを微調整することを可能にします。
コード例:
mod domain { pub struct User { pub name: String, age: u32, // プライベートフィールド } impl User { pub fn new(name: String, age: u32) -> Self { Self { name, age } } pub fn age(&self) -> u32 { self.age } } } use domain::User; fn main() { let u = User::new("Eve".to_string(), 24); println!("{} {}", u.name, u.age()); // u.age — アクセスエラー!フィールドはモジュールの外で閉じられています }
主な特徴:
構造体をpubにして、すべてのフィールドをプライベートのままにすることはできますか?モジュールの外でそのインスタンスをどのように作成しますか?
はい。通常そうします:構造体はpubであり、フィールドはプライベートで、公開コンストラクタ(例えば、pub fn new...)を通じてのみ作成されます。
pub struct Fooと宣言すると、構造体のフィールドは外部コードで見ることができますか?
いいえ、デフォルトでは各フィールドは依然としてプライベートです—フィールドに対してpubを明示的に指定する必要があります。pub structはタイプを見えるようにするだけです。
enumに対してpubは同様に機能しますか?
enumの場合、pubはすべてのバリエーションに適用されますが、バリエーション内の関連データ(例えば、Variant(value: T)のフィールド)については、内部をアクセス可能にしたい場合はpubを明示的に指定する必要があります。
ライブラリ内で構造体はpub struct Configとして宣言され、すべてのフィールドもpubになっている—ユーザーが"見える"ようにするため。結果として、外部の任意のコードが状態を任意に変更し、不変条件を壊し、突然のpanicが発生する可能性があります。
利点:
欠点:
構造体Configはpubで、すべてのフィールドはプライベートです。設定はビルダーメソッド、デフォルトコンストラクタ、またはセッター/ゲッター関数を通じてのみ可能です。モジュールの外部で不変条件を壊すことはできません。
利点:
欠点: