Code Examples in Documentation
Code examples in documentation show callers how to construct types, invoke methods, and handle return values in realistic scenarios while doubling as automated regression tests executed by cargo test --doc.
Visible in `cargo doc` HTML: Compiled by `rustdoc --test`:
+-----------------------------------+ +-----------------------------------+
| let cfg = Config::parse("p=80")?; | | # fn main() -> Result<(), Error> {|
| assert_eq!(cfg.port, 80); | | let cfg = Config::parse("p=80")?; |
+-----------------------------------+ | assert_eq!(cfg.port, 80); |
| # Ok(()) |
| # } |
+-----------------------------------+
Writing Focused Examples with Hidden # Setup Lines
A great documentation example focuses the reader's attention on the specific function or type being documented, without forcing them to read 15 lines of setup boilerplate.
Prefixing any line inside a doc code block with # (a # followed by a space, or a standalone # on an empty line) hides that line in the rendered HTML documentation while still compiling and running it during cargo test --doc:
- To write a literal
#attribute like#[derive(Debug)]inside a doc example without hiding the line, double the hash:##[derive(Debug)].
#[derive(Debug, PartialEq, Eq)]
pub struct ParseConfigError;
#[derive(Debug, PartialEq, Eq)]
pub struct ServerConfig {
pub host: String,
pub port: u16,
}
impl ServerConfig {
/// Parses a `"host:port"` string into a [`ServerConfig`].
///
/// # Examples
///
/// ```
/// # // Hidden setup: allows using `?` directly in the visible example!
/// # use my_crate::{ServerConfig, ParseConfigError};
/// # fn main() -> Result<(), ParseConfigError> {
/// let config = ServerConfig::parse("127.0.0.1:8080")?;
/// assert_eq!(config.host, "127.0.0.1");
/// assert_eq!(config.port, 8080);
/// # Ok(())
/// # }
/// ```
pub fn parse(input: &str) -> Result<Self, ParseConfigError> {
let (host, port_str) = input.split_once(':').ok_or(ParseConfigError)?;
let port = port_str.parse::<u16>().map_err(|_| ParseConfigError)?;
Ok(Self {
host: host.to_string(),
port,
})
}
}
fn main() {
let cfg = ServerConfig::parse("127.0.0.1:8080").unwrap();
println!("Parsed config: {}:{}", cfg.host, cfg.port);
}
Parsed config: 127.0.0.1:8080
Implicit Question-Mark Support in Doc Examples (Ok::<(), E>(()))
Instead of writing # fn main() -> Result<(), E> { ... # Ok(()) # }, rustdoc also recognizes when a code block ends with # Ok::<(), ErrorType>(()). When rustdoc sees that final expression, it automatically changes the generated fn main() wrapper to return Result<(), ErrorType>:
/// Parses a hexadecimal byte (`"ff"` -> `255`).
///
/// ```
/// let byte = u8::from_str_radix("ff", 16)?;
/// assert_eq!(byte, 255);
/// # Ok::<(), std::num::ParseIntError>(())
/// ```
pub fn parse_hex_byte(s: &str) -> Result<u8, std::num::ParseIntError> {
u8::from_str_radix(s, 16)
}
fn main() {
println!("0xff = {}", parse_hex_byte("ff").unwrap());
}
0xff = 255
Escaping Attributes Inside Doc Examples (##[...])
Because # hides a line, a line starting with #[derive(Debug)] is preserved as visible by rustdoc (since # is followed by [, not a space), whereas in contexts where a macro or attribute starts after # , writing ##[attribute] renders as #[attribute] in the output.