“pub”是用来表示公开到crate还是公开到module的?

5
为了使子模块的方法公开,您必须明确地重新导出它们,否则将子模块本身公开:
mod foo {
    mod bar {
        pub fn baz() {}
    }
    pub use self::bar::baz;
}

这似乎暗示了 pub 用于指示一个东西应该公开到一个模块,但是你可以选择不这样做。但是,如果你在内部上下文中使用了外部环境中定义的私有类型,并且尝试将涉及该类型的公共函数公开到内部上下文中时,即使它没有被重新导出,你也会收到错误提示。
mod foo {
    struct Foo;

    mod bar {
        use super::Foo;

        pub fn baz(foo: Foo) {}
    }
}

导致
error[E0446]: private type `Foo` in public interface
 --> src/lib.rs:7:9
  |
2 |     struct Foo;
  |     - `Foo` declared as private
...
7 |         pub fn baz(foo: Foo) {}
  |         ^^^^^^^^^^^^^^^^^^^^ can't leak private type

如何正确地使用 pub 关键字?它应该保留给真正的公共事物,还是可以用于内部模块?


2
听起来你想知道如何在一个 crate 内将 Rust 项目公开,但在 crate 外部将其设为私有?(链接:https://dev59.com/hFgR5IYBdhLWcg3wJqm7) - Shepmaster
1
pub(crate) 正是我正在寻找的。谢谢。 - dspyz
1
请注意,您可以通过使用 pub use super::Foo; 来修复编译错误。 - Jmb
1个回答

2
你的示例无法编译的原因,最终是因为RFC (136)这样说的。(另请参见问题22261
公共项目有哪些限制?
各种公共项目的规则如下:
- 如果是静态声明,则其类型中引用的项目必须为 public。 - 如果是 fn 声明,则其 trait bounds、参数类型和返回类型中引用的项目必须为 public。 - 如果是 struct 或 enum 声明,则其 trait bounds 和 pub 字段类型中引用的项目必须为 public。 - 如果是 type 声明,则其定义中引用的项目必须为 public。 - 如果是 trait 声明,则其超级 trait 中、类型参数的 trait bounds 中以及方法签名中引用的项目(参见上文中的 fn 案例)必须为 public。
简而言之,baz 不允许是 pub,因为它有一个私有类型的参数。因此,如果 bazpub,那么父模块 mod foo 就可以通过 pub use bar::baz; 来重新导出 baz。这当然是不允许的,这也是整个示例非法的原因。
一些人曾经提到过应该允许 pub fn baz,并在父模块重新导出时给出编译错误。然而,那需要更复杂的静态分析来检测,最终没有实现,因为 RFC 规定它是非法的。
"pub"指定该项可被父模块访问。如果所有模块祖先都是 "pub",那么该项将作为整个 crate 的导出项。
引用:
"pub"关键字使任何模块、函数或数据结构从外部模块中可访问。"pub"关键字也可以在"use"声明中使用,以重新导出命名空间中的标识符。
根据项是否公共或私有的概念,Rust 在两种情况下允许项访问:
1. 如果一个项是公共的,那么如果您可以从模块 m 访问所有项的祖先模块,则它可以从模块 m 外部访问。您还可以通过重新导出可能能够命名该项。见下文。
2. 如果一个项是私有的,它只能被当前模块及其子孙访问。

2
我理解 pub 如何工作的机制,但不确定何时应该使用它。 为什么编译器会在我的示例中抱怨公共接口中的私有类型? - dspyz
请注意,我已经用 conventions 标记了这个问题。 - dspyz
1
好的,给我一分钟,我会重新回答的 :) - vallentin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接