Documentação com rustdoc e doc tests
1. Introdução ao rustdoc e à documentação em Rust
Rust possui um sistema de documentação integrado e poderoso chamado rustdoc. Através do comando cargo doc, qualquer crate pode gerar documentação HTML automaticamente a partir de comentários especiais no código-fonte. Esse ecossistema promove a documentação como parte integrante do desenvolvimento, não como uma tarefa separada.
A sintaxe básica utiliza /// para documentar itens públicos (funções, structs, enums, traits) e //! para documentar o crate ou módulo como um todo. O conteúdo é escrito em Markdown, permitindo formatação rica.
/// Soma dois números inteiros.
///
/// # Exemplo
///
/// ```
/// let resultado = soma(2, 3);
/// assert_eq!(resultado, 5);
/// ```
pub fn soma(a: i32, b: i32) -> i32 {
a + b
}
//! Este crate fornece utilitários matemáticos básicos.
Para gerar a documentação localmente, execute cargo doc --open. O navegador abrirá uma página HTML completa com navegação, busca e links entre itens.
2. Escrevendo documentação rica e estruturada
Comentários de documentação suportam Markdown completo: cabeçalhos, listas, tabelas, blocos de código e links. Use [crate], [super], [crate::module::Item] para referências internas que se tornam links clicáveis na documentação gerada.
/// Uma struct que representa um ponto no espaço 2D.
///
/// # Campos
///
/// * `x` - Coordenada horizontal
/// * `y` - Coordenada vertical
///
/// # Métodos
///
/// Veja [`Ponto::distancia`] para calcular a distância até outro ponto.
///
/// # Exemplos
///
/// ```
/// use meu_crate::Ponto;
///
/// let p = Ponto { x: 3.0, y: 4.0 };
/// assert_eq!(p.x, 3.0);
/// ```
pub struct Ponto {
pub x: f64,
pub y: f64,
}
impl Ponto {
/// Calcula a distância euclidiana entre dois pontos.
pub fn distancia(&self, outro: &Ponto) -> f64 {
let dx = self.x - outro.x;
let dy = self.y - outro.y;
(dx * dx + dy * dy).sqrt()
}
}
Documente módulos com //! para descrever o propósito e a estrutura:
//! Módulo de operações geométricas.
//!
//! Contém structs e funções para trabalhar com formas geométricas
//! básicas como pontos, retas e círculos.
pub mod geometria {
// ...
}
3. Doc tests: testes embutidos na documentação
Doc tests são blocos de código dentro da documentação que o Rust compila e executa como testes. Eles garantem que os exemplos na documentação estejam sempre corretos e funcionais.
/// Divide dois números.
///
/// # Exemplo
///
/// ```
/// let resultado = divide(10, 2);
/// assert_eq!(resultado, 5);
/// ```
///
/// # Panics
///
/// A função panic se o divisor for zero:
///
/// ```should_panic
/// divide(10, 0);
/// ```
pub fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Divisão por zero");
}
a / b
}
Para executar apenas os doc tests: cargo test --doc. O Rust compila cada bloco ``` como um crate separado e executa os asserts.
Doc tests também suportam o operador ? para funções que retornam Result:
/// Lê um arquivo e retorna seu conteúdo como string.
///
/// # Exemplo
///
/// ```rust,no_run
/// # use std::fs;
/// let conteudo = ler_arquivo("exemplo.txt")?;
/// # Ok::<(), std::io::Error>(())
/// ```
pub fn ler_arquivo(caminho: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(caminho)
}
4. Boas práticas e dicas para doc tests
- Exemplos compiláveis: Sempre escreva exemplos que compilem e executem sem erros. Use
assert_eq!ouassert!para demonstrar resultados esperados. - Linhas ocultas com
#: Para esconder código de setup que não é relevante para o entendimento do exemplo, prefixe com#:
/// ```
/// # let mut v = Vec::new();
/// v.push(1);
/// assert_eq!(v.len(), 1);
/// ```
- Doc tests condicionais: Use
#[cfg(feature = "alguma_feature")]dentro do doc test para exemplos que dependem de features:
/// ```
/// # #[cfg(feature = "serde")]
/// # {
/// use serde::{Serialize, Deserialize};
/// # }
/// ```
- Evite
ignore: Prefirano_run(compila mas não executa) oucompile_fail(espera-se erro de compilação) em vez deignore, que desativa completamente o teste.
5. Personalizando a saída da documentação
Atributos especiais controlam como os itens aparecem na documentação:
/// Item público mas escondido da documentação.
#[doc(hidden)]
pub fn interna() {}
/// Permite busca por "soma" ou "adição".
#[doc(alias = "soma")]
#[doc(alias = "adição")]
pub fn somar(a: i32, b: i32) -> i32 { a + b }
/// Disponível apenas com a feature "avancado".
#[doc(cfg(feature = "avancado"))]
pub fn funcao_avancada() {}
No lib.rs, configure a aparência global:
#![doc(html_logo_url = "https://example.com/logo.png")]
#![doc(html_favicon_url = "https://example.com/favicon.ico")]
#![doc(html_root_url = "https://docs.rs/meu-crate")]
Para documentar que um bloco de código deve falhar ao compilar:
/// ```compile_fail
/// let x: i32 = "string"; // Erro intencional
/// ```
6. Documentação de crates e módulos
No lib.rs, use //! para descrever o crate inteiro:
//! # Meu Crate
//!
//! `meu_crate` é uma biblioteca para cálculos geométricos.
//!
//! ## Estrutura
//!
//! - [`geometria`] - Módulo com formas básicas
//! - [`algebra`] - Módulo com operações vetoriais
//!
//! ## Exemplo
//!
//! ```rust
//! use meu_crate::geometria::Ponto;
//! let p = Ponto::novo(1.0, 2.0);
//! ```
Para workspaces, cada crate interno deve ter sua própria documentação. Use crate::modulo::Item para referências cruzadas entre módulos do mesmo crate.
7. Ferramentas complementares e integração
cargo doc --no-deps: Gera documentação apenas do crate atual, ignorando dependências.cargo doc --document-private-items: Inclui itens privados na documentação (útil para desenvolvimento interno).cargo doc --open: Abre a documentação no navegador após gerar.- Linting de documentação: Para garantir que não haja warnings:
bash RUSTDOCFLAGS="-D warnings" cargo doc - Publicação no docs.rs: Ao publicar no crates.io, a documentação é automaticamente gerada e hospedada em
docs.rs/nome-do-crate.
8. Exemplo prático completo
Crie um crate simples com documentação rica:
//! # Calculadora
//!
//! Biblioteca para operações aritméticas básicas.
//!
//! ## Exemplo rápido
//!
//! ```rust
//! use calculadora::soma;
//! assert_eq!(soma(2, 2), 4);
//! ```
/// Soma dois números.
///
/// # Exemplo
///
/// ```
/// use calculadora::soma;
/// assert_eq!(soma(5, 3), 8);
/// ```
pub fn soma(a: i32, b: i32) -> i32 {
a + b
}
/// Divide dois números.
///
/// Retorna `None` se o divisor for zero.
///
/// # Exemplo
///
/// ```
/// use calculadora::divide;
/// assert_eq!(divide(10, 2), Some(5));
/// assert_eq!(divide(10, 0), None);
/// ```
pub fn divide(a: i32, b: i32) -> Option<i32> {
if b == 0 {
None
} else {
Some(a / b)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_soma() {
assert_eq!(soma(1, 1), 2);
}
}
Execute cargo test --doc para ver os doc tests passarem, e cargo doc --open para navegar pela documentação gerada. Note como os links funcionam e os exemplos são testados automaticamente.
Referências
- Documentação oficial do rustdoc — Guia completo sobre o sistema de documentação do Rust, incluindo sintaxe, atributos e configurações.
- The Rust Programming Language - Documentação — Capítulo do livro oficial sobre documentação de crates e publicação.
- Rust by Example - Doc Tests — Exemplos práticos de doc tests com diferentes cenários e configurações.
- docs.rs - Documentação de crates — Plataforma oficial que hospeda a documentação gerada pelo rustdoc para todos os crates publicados.
- Rustdoc Book - Atributos de documentação — Referência detalhada sobre atributos como
#[doc(hidden)],#[doc(alias)]e#[doc(cfg)]. - Guia de estilo de documentação Rust — Boas práticas e convenções para escrever documentação consistente em projetos Rust.