Введение: Почему документация в Rust — это не роскошь, а необходимость
Rust славится своей безопасной работой с памятью, производительностью и строгой системой типов. Однако даже самый элегантный код бесполезен, если никто не понимает, как его использовать. Качественная документация — это мост между вашим кодом и пользователями (включая вас самих через полгода).
К счастью, в Rust заложены мощные инструменты для автоматической генерации документации прямо из исходного кода. В этой статье мы разберём весь процесс: от простых комментариев до создания полноценной документации с примерами, ссылками и даже математическими формулами.
1. Основы: doc-комментарии и rustdoc
В Rust существует два типа комментариев: обычные (// и /* */) и документационные (/// и //!). Последние обрабатываются утилитой rustdoc, которая генерирует HTML-документацию.
1.1. Внешние и внутренние doc-комментарии
///— внешний комментарий. Пишется перед элементом (функцией, структурой, трейтом) и описывает его.//!— внутренний комментарий. Используется для документирования самого модуля, крейта или файла.
/// Вычисляет факториал числа n.
///
/// # Примеры
/// ```
/// let result = factorial(5);
/// assert_eq!(result, 120);
/// ```
pub fn factorial(n: u32) -> u32 {
(1..=n).product()
}
//! # Мой супер-крейт
//!
//! Этот крейт предоставляет утилиты для работы с математикой.
//! Подробнее смотрите в [документации](https://example.com).
1.2. Запуск генерации документации
Чтобы сгенерировать документацию, выполните команду:
cargo doc --open
Эта команда просканирует все doc-комментарии в вашем проекте, создаст HTML-файлы в папке target/doc/ и откроет их в браузере. Вы увидите страницу со списком модулей, функций и структур — всё, как на docs.rs.
2. Секции документации: как сделать её читаемой
Просто написать комментарий недостаточно. Чтобы документация была полезной, её нужно структурировать. rustdoc поддерживает Markdown, поэтому вы можете использовать заголовки, списки, ссылки и даже блоки кода.
2.1. Стандартные секции
Принято использовать следующие секции (начинаются с # ):
# Examples— один или несколько примеров использования.# Panics— в каких случаях функция вызывает панику.# Errors— если функция возвращаетResult, опишите возможные ошибки.# Safety— обязательна дляunsafeфункций.# Arguments— описание параметров (хотя часто их описывают прямо в тексте).
/// Читает содержимое файла и возвращает его как строку.
///
/// # Arguments
/// * `path` — путь к файлу.
///
/// # Errors
/// Возвращает `io::Error`, если файл не существует или недоступен для чтения.
///
/// # Panics
/// Паникует, если путь содержит нулевой байт.
///
/// # Examples
/// ```
/// let content = read_file("hello.txt").unwrap();
/// println!("{}", content);
/// ```
pub fn read_file(path: &str) -> Result<String, std::io::Error> {
std::fs::read_to_string(path)
}
2.2. Ссылки и перекрёстные ссылки
Вы можете ссылаться на другие элементы кода. rustdoc автоматически превратит их в гиперссылки:
/// Использует функцию [`factorial`] для вычисления комбинаций.
/// См. также модуль [`math::combinatorics`].
pub fn combinations(n: u32, k: u32) -> u32 {
factorial(n) / (factorial(k) * factorial(n - k))
}
Если нужно сослаться на внешний крейт, используйте полный путь, например [`std::fs::read_to_string`].
3. Тестирование документации: примеры как тесты
Одна из лучших фич Rust — примеры кода в документации автоматически компилируются и запускаются как тесты! Это гарантирует, что ваша документация не устаревает.
3.1. Запуск тестов документации
Чтобы проверить все примеры в документации, выполните:
cargo test --doc
Если пример содержит ошибку, тест упадёт, и вы узнаете об этом до того, как документация попадёт к пользователям.
3.2. Скрытие кода от тестов
Иногда нужно показать код, который не должен компилироваться (например, пример с ошибкой). Используйте атрибут ignore:
/// ```ignore
/// // Этот код не компилируется, но показывает идею
/// let x: u32 = -1; // Ошибка!
/// ```
Или no_run, если код компилируется, но не должен запускаться (например, бесконечный цикл):
/// ```no_run
/// loop {
/// println!("Бесконечность!");
/// }
/// ```
3.3. Пример с ожидаемым результатом
Вы можете использовать assert_eq! внутри примеров, чтобы явно показать ожидаемый вывод:
/// ```
/// let result = add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
4. Продвинутые техники: атрибуты, скрытие и кастомизация
4.1. Атрибуты документации
Вы можете управлять поведением rustdoc с помощью атрибутов:
#[doc(hidden)]— скрывает элемент из документации (полезно для внутренних функций).#[doc(alias = "...")]— добавляет псевдоним для поиска.#[doc(cfg(...))]