在 Rust 中,pub 关键字用于控制项(如函数、结构体、枚举、模块、常量等)的可见性(即公开程度)。Rust 默认所有项都是私有的,只有在当前模块及其子模块中可见。通过 pub 可以扩大可见范围,Rust 提供了多种 pub 限定符,允许精确控制公开的范围。
1. 默认私有性
- 不标注
pub的项默认为私有,仅在其所在的模块及其子模块中可访问。 - 父模块无法直接访问子模块的私有项。
rust
mod parent {
fn private_fn() {} // 私有,仅在 parent 模块内可见
pub mod child {
fn child_private() {} // 私有,仅在 child 模块内可见
pub fn child_public() {} // 公开
}
}
// 在外部:parent::child::child_public() 可调用,但 parent::private_fn() 不行
2. 基本 pub ------ 完全公开
pub不加限定符时,表示该项在所有地方都可见(即公开到 crate 外部)。- 对于库 crate,其他 crate 可以访问标记为
pub的项。
rust
pub fn public_function() {} // 整个 crate 以及外部 crate 可见
struct PrivateStruct; // 仅当前模块可见
3. 受限公开范围
Rust 允许通过 pub(<限定符>) 将可见性限制在特定范围内。常用的限定符有:
3.1 pub(crate)
- 该项在整个 crate 内可见(即所有模块都可访问),但对其他 crate 隐藏。
- 适用于需要在 crate 内部多处使用,但不想暴露给外部的 API。
rust
pub(crate) fn internal_util() {} // 当前 crate 的任何地方都可调用
3.2 pub(super)
- 该项仅在父模块(immediate parent)中可见。
- 相当于
pub(in super)的简写。
rust
mod parent {
pub(super) fn only_in_parent() {} // 仅在 parent 模块内可见,parent 的子模块也可访问
mod child {
fn call() {
super::only_in_parent(); // 可以访问,因为 child 是 parent 的子模块
}
}
}
// 在 parent 外部无法访问 only_in_parent
3.3 pub(in <path>)
- 将可见性限制在指定的路径所表示的模块内(包括该模块的子模块)。
<path>必须是当前模块可以访问的某个上级模块或 crate 根。
rust
mod a {
pub mod b {
pub mod c {
pub(in crate::a) fn limited() {} // 仅在 a 模块及其子模块中可见
pub(in crate::a::b) fn more_limited() {} // 仅在 b 及其子模块中可见
}
}
}
// 可以在 a 模块的任何子模块中调用 limited,但不能在 a 外部调用
4. 结构体字段的 pub
结构体的字段默认私有,即使结构体本身是公开的,其字段也需单独标记 pub 才能被外部访问。
rust
pub struct Person {
pub name: String, // 公开字段
age: u8, // 私有字段
}
impl Person {
pub fn new(name: String, age: u8) -> Self {
Person { name, age }
}
pub fn age(&self) -> u8 { // 通过公开方法访问私有字段
self.age
}
}
5. 枚举的 pub
枚举若标记为 pub,其所有变体都自动公开(因为枚举变体没有单独的可见性控制)。
rust
pub enum Color {
Red, Green, Blue // 所有变体公开
}
如果枚举本身是私有的,变体自然也是私有的。
6. 模块的 pub
pub mod将模块公开,允许外部访问模块内的公开项。- 私有模块内的项即使标记
pub也无法被外部访问,因为模块本身不可见。
rust
pub mod outer {
pub fn visible() {}
fn invisible() {}
}
// 外部可调用 outer::visible(),但不可调用 invisible
7. 可见性规则总结
- 可见性始终是"向上兼容"的:一个项的可见范围不能超过其容器的可见范围。
- 例如:私有模块内的
pub项实际上只在模块内可见(因为模块本身私有),但编译器会提示警告。 - 子模块可以访问父模块的私有项,但父模块不能访问子模块的私有项(除非通过
pub公开)。
8. 实际应用场景
| 限定符 | 用途 |
|---|---|
pub |
公开 API,供其他 crate 使用 |
pub(crate) |
内部工具函数、模块,供整个 crate 共享 |
pub(super) |
只允许父模块访问,常用于父模块控制子模块的某些逻辑 |
pub(in path) |
更精细的控制,如仅在某个模块子树内可见 |
9. 注意事项
pub不能用于局部变量(函数内定义的变量),它们总是私有于函数。- 在 trait 定义中,方法默认是公开的(trait 本身就是对外接口),但实现 trait 时方法的可见性必须与 trait 定义一致。
- 重新导出(
pub use)也会继承pub的可见性规则。
通过合理使用 pub 及其限定符,可以精确控制 Rust 项目的封装性,既保证内部实现的安全重构,又提供清晰的公共接口。