bigywater.tech
Rust · 14

模块、可见性与 pub

模块系统是 Rust 里最容易「看懂了、写不对」的部分。这篇用真实的编译器报错把规则一条条验证:什么算私有、pub 的几种范围、私有性在模块树里的方向,以及 mod 声明和磁盘文件是怎么对应的。

E0603 / E0616
访问私有函数 / 私有字段的错误
pub(super)
只有父模块可见;从外面调用被拒绝
E0583
mod 声明了却没有对应文件

默认私有

实测 · 本机执行输出
  源码:
      1 | mod bank {
      2 |     pub struct Account { pub owner: String, balance: i64 }
      3 |     impl Account {
      4 |         pub fn new(owner: &str) -> Self { Account { owner: owner.into(), balance: 0 } }
      5 |         pub fn deposit(&mut self, n: i64) { self.balance += n; }
      6 |         pub fn balance(&self) -> i64 { self.balance }
      7 |     }
      8 |     fn audit() {}            // 私有函数
      9 | }
     10 | fn main() {
     11 |     let mut a = bank::Account::new("ann");
     12 |     a.deposit(50);
     13 |     println!("{} 的余额 {}", a.owner, a.balance());
     14 |     println!("{}", a.balance);       // 私有字段
     15 |     bank::audit();                   // 私有函数
     16 | }
  编译:失败
    error[E0603]: function `audit` is private
      --> <实验目录>/src/u14a.rs:15:11
       |
    15 |     bank::audit();                   // 私有函数
       |           ^^^^^ private function
       |
    note: the function `audit` is defined here
      --> <实验目录>/src/u14a.rs:8:5
       |
     8 |     fn audit() {}            // 私有函数
       |     ^^^^^^^^^^
    
    error[E0616]: field `balance` of struct `Account` is private
      --> <实验目录>/src/u14a.rs:14:22
       |
    14 |     println!("{}", a.balance);       // 私有字段
       |                      ^^^^^^^ private field
       |
    help: a method `balance` also exists, call it with parentheses
       |
    14 |     println!("{}", a.balance());       // 私有字段
       |                             ++
    
    error: aborting due to 2 previous errors
    
    Some errors have detailed explanations: E0603, E0616.
    For more information about an error, try `rustc --explain E0603`.

pub(crate)、pub(super)

实测 · 本机执行输出
  源码:
      1 | mod outer {
      2 |     pub mod inner {
      3 |         pub(crate) fn crate_wide() -> &'static str { "pub(crate):整个 crate 可见" }
      4 |         pub(super) fn parent_only() -> &'static str { "pub(super):只有父模块 outer 可见" }
      5 |         pub fn everyone() -> &'static str { "pub:到处可见" }
      6 |     }
      7 |     pub fn call_parent_only() -> &'static str { inner::parent_only() }
      8 | }
      9 | use outer::inner::{self, everyone};
     10 | fn main() {
     11 |     println!("{}", inner::crate_wide());
     12 |     println!("{}", everyone());
     13 |     println!("{}", outer::call_parent_only());
     14 | }
  编译:成功
  运行(退出码 0):
    pub(crate):整个 crate 可见
    pub:到处可见
    pub(super):只有父模块 outer 可见
  源码:
      1 | mod outer { pub mod inner { pub(super) fn parent_only() {} } }
      2 | fn main() { outer::inner::parent_only(); }
  编译:失败
    error[E0603]: function `parent_only` is private
     --> <实验目录>/src/u14c.rs:2:27
      |
    2 | fn main() { outer::inner::parent_only(); }
      |                           ^^^^^^^^^^^ private function
      |
    note: the function `parent_only` is defined here
     --> <实验目录>/src/u14c.rs:1:29
      |
    1 | mod outer { pub mod inner { pub(super) fn parent_only() {} } }
      |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    error: aborting due to 1 previous error
    
    For more information about this error, try `rustc --explain E0603`.

私有性的方向

实测 · 本机执行输出
  源码:
      1 | mod parent {
      2 |     fn secret() -> &'static str { "父模块的私有函数" }
      3 |     pub mod child {
      4 |         pub fn peek() -> &'static str { super::secret() }   // 子模块访问祖先的私有项
      5 |         fn hidden() -> &'static str { "子模块的私有函数" }
      6 |     }
      7 |     pub fn call_child_private() -> &'static str { child::hidden() }   // 祖先访问子模块的私有项
      8 | }
      9 | fn main() { println!("{}", parent::child::peek()); println!("{}", parent::call_child_private()); }
  编译:失败
    error[E0603]: function `hidden` is private
     --> <实验目录>/src/u14d.rs:7:58
      |
    7 |     pub fn call_child_private() -> &'static str { child::hidden() }   // 祖先访问子模块的私有项
      |                                                          ^^^^^^ private function
      |
    note: the function `hidden` is defined here
     --> <实验目录>/src/u14d.rs:5:9
      |
    5 |         fn hidden() -> &'static str { "子模块的私有函数" }
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    error: aborting due to 1 previous error
    
    For more information about this error, try `rustc --explain E0603`.

模块与文件

实测 · 本机执行输出
  目录:src/main.rs  src/util.rs  src/net/mod.rs  src/net/client.rs
  $ cargo run -q
    来自 util.rs
    来自 net/client.rs
  mod nothere; 但没有 nothere.rs:
       Compiling modmissing v0.1.0 (<实验目录>/proj/modmissing)
    error[E0583]: file not found for module `nothere`
     --> src/main.rs:1:1
      |
    1 | mod nothere;
      | ^^^^^^^^^^^^
      |
      = help: to create the module `nothere`, create file "src/nothere.rs" or "src/nothere/mod.rs"
      = note: if there is a `mod nothere` elsewhere in the crate already, import it with `use crate::...` instead
    

crate、package、workspace 的关系见Crate、Package 与 Workspace。

分步演示

模块与可见性
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。前三节用 rustc 单文件编译,第四节用 cargo 项目验证目录结构
    • 没有验证:pub(in path)、use 的重导出 pub use、use 的 glob 导入与命名冲突、#[path] 属性、测试模块 #[cfg(test)] mod tests 对私有项的访问
    京ICP备2026067502号-1京公网安备11010502063487号