Skip to content
← All Rust articles

Rust explainer

Comments, doc comments, and how to read docs.rs

About 5 min to read. Allow extra time to work through examples.

Use comments to explain decisions, doc comments to describe APIs, and doctests to check examples. Learn what rustdoc verifies and what to look for on a documentation page.

This article uses Rust. You can make it your practice mode to browse related content across the site.

Rust uses ordinary comments for notes in source code and doc comments for documentation attached to a module or item. Knowing the difference helps you write useful explanations and read generated API pages.

Ordinary comments and documentation

// starts a line comment. /* ... */ is a block comment, and block comments can nest. Their contents are not executable Rust code.

/// documents the item that follows it. //! documents its enclosing crate or module and belongs before that module's items. This complete program shows both placements:

//! Small parsing example.

// Ordinary notes do not become API documentation.
/* A block comment can contain /* another block comment */ inside it. */

/// Parses a decimal integer, returning None when parsing fails.
fn parse(input: &str) -> Option<u32> {
    input.parse().ok()
}

fn main() {
    assert_eq!(parse("12"), Some(12));
    assert_eq!(parse("bad"), None);
}

The block forms /** ... */ and /*! ... */ provide outer and inner documentation respectively. Outer documentation is equivalent to a #[doc = "..."] attribute; inner documentation uses #![doc = "..."]. A dangling outer doc comment has no item to attach to and causes a compiler error. Remove it, restore the item, or change it to an ordinary comment.

Write an example that can be tested

Rustdoc renders Markdown, including supported extensions such as tables. For a library crate named mylib, put this in src/lib.rs:

/// Adds two bytes and returns a sum that fits in u16.
///
/// # Examples
///
/// ```
/// use mylib::add_bytes;
/// assert_eq!(add_bytes(200, 100), 300);
/// ```
pub fn add_bytes(a: u8, b: u8) -> u16 {
    u16::from(a) + u16::from(b)
}

cargo doc --open builds and opens the generated documentation. cargo test --doc runs the library's enabled documentation tests. Normal Rust example blocks are compiled and executed; assertions check their results. Use your actual crate name in an example that imports its API.

Tests help keep examples accurate when they are run, but do not make every published example correct. Features, target platforms, ignored tests and CI configuration affect what gets checked. A docs.rs page is rendered documentation, not proof that every example passed in your environment.

Read the code-fence attributes

Attribute Doctest behavior
Ordinary Rust block Compile and run.
no_run Compile without running.
ignore Skip by default; document the reason.
should_panic Compile and expect execution to panic.
compile_fail Expect compilation to fail.
text Treat the block as text, not a Rust test.

Inside a Rust doctest, a line prefixed with # can supply hidden setup: it participates in compilation but is omitted from the normal rendered example. Use ## to escape a leading hash when necessary. This convention does not make every Rust line beginning with # invisible.

Prefer a runnable example when practical. no_run can suit code needing an external service; an ignored example should explain what prevents testing it. A compile_fail example can start compiling after language changes, so it needs maintenance too.

What the site checks

This site's Rust runner compiles a generated source file with rustc and checks learner diagnostics with clippy-driver. It does not run Cargo doctests or build rustdoc pages as part of submission grading. Cargo may still be installed on your machine; it simply is not the build path used by this runner.

Doc comments can affect compilation and linting. Placement errors are one example; missing safety documentation on public unsafe APIs can also trigger Clippy. Do not assume every issue in a doc comment is invisible to the gate. Check doctests separately in a library project when you want their validation.

Make API documentation useful

Start with a short summary paragraph that makes sense in a list of items. Add sections that answer the questions a caller needs resolved:

  • Examples: typical use, with meaningful assertions where possible.
  • Errors: when a fallible operation returns each relevant error.
  • Panics: known panic conditions and how callers can avoid them.
  • Safety: obligations callers must meet before invoking an unsafe API.

Clippy has documentation lints, but they neither prove the prose correct nor enforce every necessary invariant. Enabled lint groups and item visibility affect which diagnostics appear.

When reading docs.rs, first check the crate version and available feature or platform information. Read the signature alongside the behavior and examples. Distinguish shared access (&self), exclusive access (&mut self) and a by-value receiver (self). A by-value receiver does not always make the original binding unusable: a Copy receiver can be copied into the call.

Check relevant error, panic and safety sections before relying on an API. Follow a source link when implementation details help, while remembering that an observed implementation detail is not necessarily a public guarantee.

Use source comments for decisions and constraints

Explain information that would otherwise be hard to recover: why order must be preserved, which input invariant a calculation relies on, or why a tempting alternative was rejected. Link to a specification or issue when it supports the decision. Avoid unsupported claims such as one collection always being faster than another.

A comment that merely repeats obvious code adds little. A comment explaining intent can prevent a future change from breaking an assumption. Keep both source comments and public documentation updated when behavior changes.

step 5 of 6

Orientation and the Gate

Up next Learning Rust from another language