13-简便的文档初始化

简便的文档初始化 — Rust Design Patterns

译文 · 基于 Rust Design Patterns

原文链接: https://rust-unofficial.github.io/patterns/idioms/rustdoc-init.html

简便的文档初始化

描述

如果在写文档时初始化某个结构体很费功夫,用一个以该结构体为参数的辅助函数把示例包起来会更快。

动机

有时结构体带有多个或复杂的参数,以及若干方法。这些方法各自都应当有示例。

例如:

struct Connection {
    name: String,
    stream: TcpStream,
}

impl Connection {
    /// 通过该连接发送请求。
    ///
    /// # 示例
    /// ```no_run
    /// # // 需要样板代码才能让示例跑起来。
    /// # let stream = TcpStream::connect("127.0.0.1:34254");
    /// # let connection = Connection { name: "foo".to_owned(), stream };
    /// # let request = Request::new("RequestId", RequestType::Get, "payload");
    /// let response = connection.send_request(request);
    /// assert!(response.is_ok());
    /// ```
    fn send_request(&self, request: Request) -> Result<Status, SendErr> {
        // ...
    }

    /// 糟糕,所有这些样板代码都得在这里再写一遍!
    fn check_status(&self) -> Status {
        // ...
    }
}

示例

与其敲下所有这些样板代码来创建 Connection 和 Request,不如写一个包装辅助函数,把它们作为参数传入,这样更轻松:

struct Connection {
    name: String,
    stream: TcpStream,
}

impl Connection {
    /// 通过该连接发送请求。
    ///
    /// # 示例
    /// ```
    /// # fn call_send(connection: Connection, request: Request) {
    /// let response = connection.send_request(request);
    /// assert!(response.is_ok());
    /// # }
    /// ```
    fn send_request(&self, request: Request) -> Result<Status, SendErr> {
        // ...
    }
}

注意:在上面的示例中,assert!(response.is_ok()); 这一行在测试时实际上不会运行,因为它位于一个从未被调用的函数内部。

优点

这样简洁得多,并且避免了示例中的重复代码。

缺点

由于示例位于函数中,这段代码不会被实际测试。不过在运行 cargo test 时仍会检查它能否编译。因此,当你需要 no_run 时,这一模式最有用。有了它,你就不必再加 no_run。

讨论

如果不需要断言,这一模式效果很好。

如果需要断言,一种替代做法是创建一个用于构造辅助实例的公开方法,并用 #[doc(hidden)] 标注(这样用户看不到它)。然后该方法可以在 rustdoc 中调用,因为它是 crate 公开 API 的一部分。

最后修改 August 21, 2026: 更新 (76fc81a2e)