重新导出

让我们从解释什么是重新导出开始。为此,我们将使用一个例子,其中我们正在编写一个库(名为lib),其中一些类型分布在子模块中

#![allow(unused)]
fn main() {
pub mod sub_module1 {
    pub struct Foo;
}
pub mod sub_module2 {
    pub struct AnotherFoo;
}
}

用户可以像这样导入它们

use lib::sub_module1::Foo;
use lib::sub_module2::AnotherFoo;

但是,如果您希望这些类型直接在 crate 根目录中可用,或者我们不希望这些模块对用户可见,该怎么办?这就是重新导出发挥作用的地方

// `sub_module1` and `sub_module2` are not visible outside.
mod sub_module1 {
    pub struct Foo;
}
mod sub_module2 {
    pub struct AnotherFoo;
}
// We re-export both types:
pub use crate::sub_module1::Foo;
pub use crate::sub_module2::AnotherFoo;

现在用户将能够这样做

use lib::{Foo, AnotherFoo};

由于 sub_module1sub_module2 都是私有的,因此用户将无法导入它们。

现在有趣的是,为此 crate 生成的文档将直接在 crate 根目录显示 FooAnotherFoo,这意味着它们已被内联。有一些规则需要了解重新导出的项是否会被内联。

内联规则

如果一个公共项来自私有模块,它将被内联

mod private_module {
    pub struct Public;
}
pub mod public_mod {
    // `Public` will inlined here since `private_module` is private.
    pub use super::private_module::Public;
}
// `Public` will not be inlined here since `public_mod` is public.
pub use self::public_mod::Public;

同样,如果一个项从其任何祖先继承了 #[doc(hidden)],它将被内联

#[doc(hidden)]
pub mod public_mod {
    pub struct Public;
}
// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`.
pub use self::public_mod::Public;

如果一个项具有 #[doc(hidden)],它将不会被内联(也不会在生成的文档中可见)

// This struct won't be visible.
#[doc(hidden)]
pub struct Hidden;

// This re-export won't be visible.
pub use self::Hidden as InlinedHidden;

同样的规则也适用于重新导出本身:如果您有多个重新导出,并且其中一些具有 #[doc(hidden)],那么这些(且仅这些)将不会出现在文档中

mod private_mod {
    /// First
    pub struct InPrivate;
}

/// Second
#[doc(hidden)]
pub use self::private_mod::InPrivate as Hidden;
/// Third
pub use self::Hidden as Visible;

在这种情况下,InPrivate 将被内联为 Visible。但是,它的文档将是 First Third 而不是 First Second Third,因为具有 Second 作为文档的重新导出具有 #[doc(hidden)],因此,它的所有属性都将被忽略。

使用 #[doc(inline)] 进行内联

如果您想强制内联一个项,可以使用 #[doc(inline)] 属性

pub mod public_mod {
    pub struct Public;
}
#[doc(inline)]
pub use self::public_mod::Public;

使用这段代码,即使 public_mod::Public 是公开的并且存在于文档中,Public 类型也会同时出现在 crate 根目录和 public_mod 模块中。

使用 #[doc(no_inline)] 防止内联

#[doc(inline)] 属性相反,如果您想防止一个项被内联,可以使用 #[doc(no_inline)]

mod private_mod {
    pub struct Public;
}
#[doc(no_inline)]
pub use self::private_mod::Public;

在生成的文档中,您将看到 crate 根目录上的重新导出,而不是直接看到类型。

属性

当一个项被内联时,它的文档注释和大多数属性将随之一起内联

mod private_mod {
    /// First
    #[cfg(a)]
    pub struct InPrivate;
    /// Second
    #[cfg(b)]
    pub use self::InPrivate as Second;
}

/// Third
#[doc(inline)]
#[cfg(c)]
pub use self::private_mod::Second as Visible;

在这种情况下,Visible 的文档将为 First Second Third,并且其 cfg 将为:#[cfg(a, b, c)]

内部文档链接 是相对于定义文档注释的位置来解析的。

但是,有一些属性不会被内联

  • #[doc(alias="")]
  • #[doc(inline)]
  • #[doc(no_inline)]
  • #[doc(hidden)](因为重新导出本身及其属性被忽略)。

当内联时,所有其他属性都会被继承,以便文档的行为与直接在显示的位置定义内联项的行为相匹配。

如果该项通过 glob 重新导出内联,这些规则也适用

mod private_mod {
    /// First
    #[cfg(a)]
    pub struct InPrivate;
}

#[cfg(c)]
pub use self::private_mod::*;

否则,显示的属性将来自重新导出的项,而重新导出本身的属性将被忽略

mod private_mod {
    /// First
    #[cfg(a)]
    pub struct InPrivate;
}

#[cfg(c)]
pub use self::private_mod::InPrivate;

在上述情况下,cfg(c) 将不会显示在文档中。