【Rust可见性控制:pub、pub(crate)、pub(super)实战】

在 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 项目的封装性,既保证内部实现的安全重构,又提供清晰的公共接口。

相关推荐
Mr_Xuhhh3 分钟前
深入理解Java抽象类与接口:从概念到实战
java·开发语言
萝卜白菜。24 分钟前
TongWeb7.0相同的类指明加载顺序
开发语言·python·pycharm
wb0430720125 分钟前
使用 Java 开发 MCP 服务并发布到 Maven 中央仓库完整指南
java·开发语言·spring boot·ai·maven
Rsun0455126 分钟前
设计模式应该怎么学
java·开发语言·设计模式
良木生香43 分钟前
【C++初阶】:C++类和对象(下):构造函数promax & 类型转换 & static & 友元 & 内部类 & 匿名对象 & 超级优化
c语言·开发语言·c++
5系暗夜孤魂1 小时前
系统越复杂,越需要“边界感”:从 Java 体系理解大型工程的可维护性本质
java·开发语言
无巧不成书02181 小时前
C语言零基础速通指南 | 1小时从入门到跑通完整项目
c语言·开发语言·编程实战·c语言入门·零基础编程·c语言速通
nbwenren2 小时前
Springboot中SLF4J详解
java·spring boot·后端
三雷科技2 小时前
使用 `dlopen` 动态加载 `.so` 文件
开发语言·c++·算法
wellc2 小时前
java进阶知识点
java·开发语言