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

相关推荐
阿蒙Amon2 小时前
C#常用类库-详解CsvHelper
开发语言·数据库·c#
刚入坑的新人编程2 小时前
C++qt(3)-按钮类控件
开发语言·c++·qt
开始了码2 小时前
基于 Qt 实现多客户端 TCP 通信聊天室
开发语言·数据库·php
一只空白格2 小时前
ThreadLocal的作用和底层原理
java·开发语言·jvm
今天你TLE了吗2 小时前
JVM学习笔记:第九章——StringTable字符串常量池
java·jvm·笔记·后端·学习
1104.北光c°2 小时前
JVM虚拟机【八股篇】:类加载机制与性能调优
java·开发语言·jvm·笔记·程序人生·调优·双亲委派
范特西.i2 小时前
QT聊天项目(11)
开发语言·qt
九尾狐ai2 小时前
从青鸟文化案例看校园文化建设的技术架构与实现方案
开发语言·python