问题背景:
在像 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 只使类型可见。
pub 对于枚举是否也适用?
对于枚举,pub 会传播到所有变体,但对于变体中的关联数据(例如,Variant(value: T) 内的字段),仍然需要显式指定 pub,如果希望使内部内容可访问。
在库中,结构体被声明为 pub struct Config,所有字段也为 pub——以便用户能够“看到”它们。结果,任何外部代码都可以任意更改状态,破坏不变性,导致 panic。
优点:
缺点:
Config 结构体为 pub,所有字段都为私有。只能通过构建器方法、默认构造函数或 setter/getter 函数进行设置。外部模块无法破坏不变性。
优点:
缺点: