在下面的示例中,模块
outer
有一个私有类型 Private
和一个私有内部模块 inner
。 inner
能够访问Private
(因为子模块可以访问其父级的私有项目,即使它们没有停放为公共)。
inner
定义了一个函数not_really_public_interface()
。虽然它被标记为公开,但它实际上只对outer
可用,因为inner
本身不是公开的。
outer.rs
struct Private;
mod inner {
use super::Private;
pub fn not_really_public_interface() -> Private {
Private
}
}
编译没有任何问题。
outer
应该可以使用inner::not_really_public_interface()
来获取Private
,只要确保不导出即可。那么让我们这样做吧:
pub fn main() {
let _ = self::inner::not_really_public_interface();
}
对吗?
标准错误
error[E0446]: private type `Private` in public interface
--> src/outer.rs:4:3
|
4 | / pub fn not_really_public_interface() -> Private {
5 | | Private
6 | | }
| |___^ can't leak private type
Wat。 这对我来说是违反直觉的,原因如下:
outer
尝试使用此功能时,才会发生该错误。inner
是定义它的模块。
到底发生了什么事情导致 Rust 得出此接口的任何部分存在泄漏的结论?看起来它对待
Private
Private
中定义的一样。是否有一个上下文可以让这句话完全有意义?我的第一个想法是这是编译器中的错误或隐私设计中的疏忽,但我怀疑情况确实如此。inner
Private
中公开 outer
,但我不想这样做。
inner
是公共的,因此它可以被任何其他模块使用。但是
not_really_public_interface
结构只能由您的 root 和 Private
模块访问。如果导入另一个模块,就会发生泄漏
inner
。 Rust 抱怨这种“可能”发生,因为它在本地报告错误,而不是对所有模块和板条箱中的所有用法采取“全局”视图。最终,这种方法对于人类来说推理起来更具可预测性,对于机器来说速度更快。
Rust 可以让你更精确地控制可见性。如果你告诉它该函数仅可用于上一级模块(
not_really_public_interface
模块),那么它就知道不存在泄漏的可能性:
super
您还可以使用
mod inner {
use super::Private;
pub(super) fn not_really_public_interface() -> Private { Private }
}
代替
crate
,来表示同一个 crate 中的任何模块。或者,如果超级模块有一个名称,例如
super
,您可以使用my_mod
来专门针对它。在我的例子中,一个更简单的解决方案是将
pub(in ::my_mod)
pub