Doc Comments (triple-slash and bang)
Rust provides two placement styles for documentation comments: outer doc comments (///), which document the item that immediately follows them, and inner doc comments (//!), which document the enclosing crate or module that contains them.
src/lib.rs
+-------------------------------------------------------------------+
| //! # My Networking Crate <-- INNER (`//!`): |
| //! High-level overview of the Documents the enclosing |
| //! entire crate. `lib.rs` crate root! |
| |
| /// A TCP endpoint configuration. <-- OUTER (`///`): |
| /// Holds host and port settings. Documents `struct Endpoint`|
| pub struct Endpoint { immediately below it! |
| /// Hostname or IP literal. <-- OUTER (`///`): |
| pub host: String, Documents field `host` |
| /// TCP port number. |
| pub port: u16, |
| } |
+-------------------------------------------------------------------+
Comparing /// (Outer) and //! (Inner)
| Syntax | Placement | Typical Use Cases |
|---|---|---|
/// |
Placed above the target item | Functions (fn), structs, struct fields, enums, enum variants, traits, methods, constants, macros, and pub mod foo; declarations. |
//! |
Placed inside the top of a file or mod { ... } block |
Crate root (src/lib.rs), module files (src/network.rs or src/network/mod.rs), providing high-level architecture guides and crate-wide examples. |
Documenting Modules, Structs, Fields, and Enums Together
In rustdoc output, the first paragraph of any /// or //! comment is rendered as the short summary sentence in module index tables. Keep the opening paragraph to a single concise sentence before adding a blank /// line and detailed paragraphs.
//! Arithmetic and bounded counter primitives.
//!
//! This module provides saturating counters that never wrap around.
/// A counter bounded by an inclusive maximum value.
///
/// Once the counter reaches `max`, subsequent increments saturate at `max`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BoundedCounter {
/// Current value of the counter (`0 <= current <= max`).
pub current: u32,
/// Maximum allowed value for `current`.
pub max: u32,
}
/// Possible outcomes of a counter step operation.
#[derive(Debug, PartialEq, Eq)]
pub enum StepOutcome {
/// The counter advanced by 1 to the contained value.
Advanced(u32),
/// The counter was already at its maximum bound.
Saturated,
}
impl BoundedCounter {
/// Creates a new `BoundedCounter` initialized to `0` with upper bound `max`.
pub const fn new(max: u32) -> Self {
Self { current: 0, max }
}
/// Advances the counter by `1` unless it has already reached `self.max`.
pub fn step(&mut self) -> StepOutcome {
if self.current < self.max {
self.current += 1;
StepOutcome::Advanced(self.current)
} else {
StepOutcome::Saturated
}
}
}
fn main() {
let mut counter = BoundedCounter::new(1);
println!("First step: {:?}", counter.step());
println!("Second step: {:?}", counter.step());
}
First step: Advanced(1)
Second step: Saturated
Avoiding Accidental Mixing of /// and //!
A common mistake when writing module-level documentation at the top of src/lib.rs is typing /// instead of //!. If you write /// Crate overview at the top of src/lib.rs above use std::collections::HashMap;, that comment attaches to the use import (or to the first struct in the file) instead of the crate root! Always use //! at the top of src/lib.rs for crate-level documentation.