Написание документации для Rust проекта: от основ до продвинутых техник
Документирование кода — неотъемлемая часть профессиональной разработки на Rust. Благодаря встроенному инструменту rustdoc, создание качественной документации становится простым и эффективным процессом. В этой статье мы разберём, как правильно писать документацию для Rust-проектов, используя все возможности экосистемы.
Основы документирования в Rust
Rust использует особый синтаксис для документации, который основан на Markdown. Документация пишется с помощью doc-комментариев, которые начинаются с /// (для внешней документации) или //! (для внутренней документации модулей).
Рассмотрим базовый пример:
/// Вычисляет факториал числа.
///
/// Эта функция принимает целое неотрицательное число `n`
/// и возвращает его факториал. Если `n` равно 0, возвращается 1.
///
/// # Примеры
///
/// ```
/// let result = factorial(5);
/// assert_eq!(result, 120);
/// ```
pub fn factorial(n: u64) -> u64 {
(1..=n).product()
}
//! # Модуль математических функций
//!
//! Этот модуль содержит базовые математические операции,
//! включая вычисление факториала и биномиальных коэффициентов.
pub mod math;
Генерация документации с помощью rustdoc
Инструмент rustdoc входит в стандартный набор инструментов Rust и автоматически генерирует HTML-документацию из doc-комментариев. Для запуска достаточно выполнить команду:
cargo doc --open
Эта команда сгенерирует документацию для вашего проекта и всех его зависимостей, после чего откроет её в браузере. Вы также можете указать дополнительные флаги:
--no-deps— не включать документацию зависимостей--document-private-items— документировать приватные элементы--target-dir— указать директорию для выходных файлов
Сгенерированная документация автоматически включает навигацию, поиск, ссылки на типы и функции, а также тесты из примеров кода.
Структура doc-комментариев и специальные секции
Качественная документация в Rust следует определённой структуре. Рекомендуется использовать следующие секции:
- Краткое описание — первая строка комментария, отображается в списках и поиске
- Подробное описание — поясняет работу функции, её особенности и ограничения
# Examples— один или несколько примеров использования# Panics— ситуации, в которых функция может вызвать панику# Errors— возможные ошибки и их обработка# Safety— для unsafe функций: объяснение предусловий безопасности
Пример полноценной документации функции:
/// Разделяет строку на части по указанному разделителю.
///
/// Возвращает вектор строк, полученных после разделения
/// исходной строки `text` по каждому вхождению `delimiter`.
/// Пустые строки не включаются в результат.
///
/// # Examples
///
/// ```
/// let result = split_string("a,b,c", ',');
/// assert_eq!(result, vec!["a", "b", "c"]);
/// ```
///
/// # Panics
///
/// Функция паникует, если `delimiter` является пустой строкой.
///
/// # Errors
///
/// Эта функция не возвращает ошибок, но может вызвать панику.
pub fn split_string(text: &str, delimiter: char) -> Vec<String> {
assert!(delimiter != '\0', "Разделитель не может быть нулевым символом");
text.split(delimiter)
.filter(|s| !s.is_empty())
.map(|s| s.to_string())
.collect()
}
Тестирование документации
Одна из сильных сторон Rust — возможность тестировать примеры кода прямо в документации. Команда cargo test автоматически запускает все примеры из doc-комментариев как тесты. Это гарантирует, что документация всегда актуальна.
Вы можете управлять поведением тестов с помощью атрибутов:
```ignore— не тестировать пример```no_run— скомпилировать, но не запускать```should_panic— ожидать панику при выполнении```compile_fail— ожидать ошибку компиляции
Пример с атрибутами:
/// # Examples
///
/// ```should_panic
/// // Этот пример должен вызвать панику
/// let _v = vec![1, 2, 3];
/// let _x = _v[10]; // выход за границы
/// ```
///
/// ```compile_fail
/// // Этот код не должен компилироваться
/// let x: i32 = "string";
/// ```
Документирование модулей, структур и трейтов
Документирование не ограничивается функциями. Вы также должны документировать модули, структуры, перечисления, трейты и их реализации.
Пример документации структуры:
/// Представляет точку в двумерном пространстве.
///
/// # Fields
///
/// * `x` — координата по оси X
/// * `y` — координата по оси Y
///
/// # Examples
///
/// ```
/// let point = Point::new(3.0, 4.0);
/// assert_eq!(point.x, 3.0);
/// ```
#[derive(Debug, Clone, Copy)]
pub struct Point {
pub x: f64,
pub y: f64,
}
impl Point {
/// Создаёт новую точку с заданными координатами.
pub fn new(x: f64, y: f64) -> Self {
Point { x, y }
}
/// Вычисляет расстояние от начала координат до точки.
pub fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
Для трейтов также важно указывать контракт, который должны выполнять реализации:
/// Трейт для объектов, которые можно сериализовать в JSON.
///
/// # Implementing
///
/// Реализация должна преобразовывать структуру в корректный JSON-объект.
/// Поля должны быть отсортированы по алфавиту.
pub trait ToJson {
/// Сериализует объект в строку JSON.
fn to_json(&self) -> String;
}
Заключение
Написание качественной документации — важный навык для любого Rust-разработчика. Используя rustdoc