06-可见性与私有性
5 分钟阅读
译文 · 基于 The Rust Reference
原文链接: https://doc.rust-lang.org/reference/visibility-and-privacy.html
r[vis]
可见性与私有性
r[vis.syntax]
Visibility ->
`pub`
| `pub` `(` `crate` `)`
| `pub` `(` `self` `)`
| `pub` `(` `super` `)`
| `pub` `(` `in` SimplePath `)`
r[vis.intro] 这两个术语经常互换使用,它们试图传达的是对“这个项能在这个位置使用吗?”这一问题的回答。
r[vis.name-hierarchy] Rust 的名称解析在命名空间的全局层级上运行。层级中的每一级都可以看作是某个项。这些项是上文提到的那些,但也包括外部 crate。声明或定义一个新模块,可以看作是在定义处向该层级中插入一棵新树。
r[vis.privacy] 为了控制接口是否可以跨模块使用,Rust 会检查每一处对项的使用,以判断是否应被允许。私有性警告就是在此处生成的,或者说是“你使用了另一个模块的私有项,但不被允许”。
r[vis.default]
默认情况下,一切都是私有的,但有两个例外:pub Trait 中的关联项默认公开;pub 枚举中的枚举变体默认也公开。当一个项被声明为 pub 时,可以认为它对外部世界可访问。例如:
| |
r[vis.access] 基于项是公开还是私有这一概念,Rust 在两种情况下允许访问项:
- 若一个项是公开的,那么只要能从某个模块
m访问该项的所有祖先模块,就可以从m外部访问该项。也可能通过再导出来命名该项。见下文。 - 若一个项是私有的,则当前模块及其后代可以访问它。
这两种情况在创建对外暴露公开 API 同时隐藏内部实现细节的模块层级时出人意料地强大。为帮助说明,下面是一些用例及其含义:
库开发者需要把功能暴露给链接其库的 crate。作为第一种情况的结果,这意味着任何外部可用的东西,从根到目标项必须都是
pub。链中的任何私有项都会禁止外部访问。crate 需要一个对自己全局可用的“辅助模块”,但不想把该辅助模块暴露为公开 API。为此,crate 层级的根处会有一个私有模块,该模块内部再拥有“公开 API”。因为整个 crate 都是根的后代,所以整个本地 crate 都可以通过第二种情况访问这个私有模块。
为模块编写单元测试时,常见做法是给被测模块加一个名为
mod test的直接子模块。该模块可以通过第二种情况访问父模块的任何项,这意味着内部实现细节也可以从该子模块无缝测试。
第二种情况提到私有项“可以被”当前模块及其后代访问,但访问一个项的确切含义取决于该项是什么。
r[vis.use] 例如,访问一个模块意味着查看其内部(以导入更多项)。另一方面,访问一个函数意味着调用它。此外,路径表达式和导入语句也被视为访问一个项:仅当目标位于当前可见性作用域内时,该导入/表达式才有效。
下面是一段示例程序,它例证了上述三种情况:
| |
要使 Rust 程序通过私有性检查,所有路径都必须是上述两条规则下的有效访问。这包括所有 use 语句、表达式、类型等。
r[vis.scoped]
pub(in path)、pub(crate)、pub(super) 和 pub(self)
r[vis.scoped.intro]
除了公开和私有之外,Rust 还允许用户将项声明为仅在给定作用域内可见。pub 限制的规则如下:
r[vis.scoped.in]
pub(in path)使项在所提供的path内可见。path必须是解析到正在声明可见性的项的某个祖先模块的简单路径。path中的每个标识符都必须直接指代一个模块(而不是由use语句引入的名称)。
r[vis.scoped.crate]
pub(crate)使项在当前 crate 内可见。
r[vis.scoped.super]
pub(super)使项对父模块可见。这等价于pub(in super)。
r[vis.scoped.self]
pub(self)使项对当前模块可见。这等价于pub(in self),或者根本不使用pub。
r[vis.scoped.edition2018]
[!EDITION-2018] 从 2018 edition 开始,
pub(in path)的路径必须以crate、self或super开头。2015 edition 还可以使用以::开头的路径,或从 crate 根出发的模块。
下面是一个例子:
| |
注意 此语法只是给项的可见性额外增加了一层限制。它并不保证该项在指定作用域的所有部分都可见。要访问一个项,直到当前作用域为止的所有父项也必须仍然可见。
r[vis.reexports]
再导出与可见性
r[vis.reexports.intro]
Rust 允许通过 pub use 声明公开再导出项。因为这是公开声明,所以允许根据上述规则在当前模块中使用该项。它本质上允许对再导出的项进行公开访问。例如,下面的程序是有效的:
| |
这意味着任何外部 crate 引用 implementation::api::f 都会因违反私有性而报错,而路径 api::f 则被允许。
r[vis.reexports.private-item] 再导出私有项时,可以认为是允许“私有性链”通过再导出被短路,而不是像通常那样穿过命名空间层级。