Введение: почему code review в Rust — это не просто формальность
Code review — один из ключевых процессов в разработке любого качественного ПО. Но когда речь заходит о Rust, этот процесс приобретает особое значение. Rust — язык с уникальной системой владения (ownership) и заимствования (borrowing), который компилятор проверяет на этапе компиляции. Однако даже если код компилируется, это не значит, что он написан хорошо, безопасно и эффективно.
В этой статье мы разберём, на что именно обращать внимание при code review Rust-проектов, как давать конструктивную обратную связь, чтобы не обидеть коллегу, и как избежать типичных ошибок, которые не ловит компилятор. Статья ориентирована на разработчиков, которые уже знакомы с основами Rust, но хотят углубить свои навыки ревью.
1. Безопасность памяти и управление ресурсами
Rust гарантирует безопасность памяти без сборщика мусора. Но это не отменяет необходимости проверять, как разработчик использует unsafe блоки, сырые указатели и внешние FFI-вызовы.
Что проверять:
- Использование
unsafe: каждыйunsafeблок должен быть оправдан и снабжён комментарием, почему он безопасен. Если можно обойтись безunsafe— лучше так и сделать. - Утечки ресурсов: проверяйте, что все
Box,Rc,Arcи другие умные указатели корректно освобождаются. Например, циклические ссылки черезRcбезWeak— частая проблема. - Drop-порядок: если структура содержит поля с кастомной реализацией
Drop, убедитесь, что порядок уничтожения не приведёт к ошибкам.
// Пример плохого кода: unsafe без комментариев
unsafe {
let ptr = ...;
// Нет объяснения, почему это безопасно
*ptr = 42;
}
// Хороший код: комментарий и безопасная альтернатива
// Используем unsafe только для вызова C-функции, которая гарантирует валидность указателя
unsafe {
// Указатель получен из C API, который гарантирует его валидность в течение жизни вызова
some_c_function(ptr);
}
2. Идиоматичность кода и стиль
Rust имеет свои идиомы, которые отличаются от C++ или Python. Code review должен проверять, насколько код соответствует духу языка.
Что проверять:
- Использование
OptionиResult: избегайтеunwrap()иexpect()без явной причины. В production-коде используйте обработку ошибок черезmatch,?оператор илиunwrap_or_else. - Pattern matching: предпочитайте
if letиmatchвместо цепочекis_some()/is_ok(). - Использование трейтов: проверяйте, что трейты реализованы осмысленно. Например, реализация
Displayдолжна давать читаемый вывод, а не простоDebug. - Именование: в Rust принято использовать
snake_caseдля переменных и функций,CamelCaseдля типов и трейтов. Константы —SCREAMING_SNAKE_CASE.
// Плохо: избыточное использование unwrap
let value = some_option.unwrap();
// Хорошо: обработка ошибок
let value = match some_option {
Some(v) => v,
None => return Err("Value not found".into()),
};
// Ещё лучше: с оператором ?
let value = some_option.ok_or("Value not found")?;
3. Производительность и аллокации
Rust даёт низкоуровневый контроль над памятью, но это не значит, что код автоматически быстр. На ревью важно проверять потенциальные узкие места.
Что проверять:
- Лишние аллокации: проверяйте, не создаётся ли
StringилиVecтам, где можно использовать слайсы (&str,&[T]). - Клонирование:
clone()— частый источник лишних копий. Если тип реализуетCopy, это не страшно, но для больших структур лучше передавать по ссылке. - Итераторы vs циклы: итераторы в Rust часто так же быстры, как ручные циклы, но код с ними чище. Однако проверяйте, что цепочки итераторов не создают лишних промежуточных коллекций (например,
.collect()без необходимости). - Блокировки: если используются
MutexилиRwLock, проверьте, что блокировка удерживается минимальное время.
// Плохо: лишнее клонирование
fn process(data: &Vec<String>) {
let cloned = data.clone(); // копируем весь вектор
for item in cloned {
// ...
}
}
// Хорошо: работаем по ссылке
fn process(data: &[String]) {
for item in data {
// ...
}
}
4. Как давать обратную связь: конструктивно и без обид
Code review — это не только техническая проверка, но и коммуникация. В Rust-сообществе принято быть вежливым и помогать коллегам расти.
Принципы хорошей обратной связи:
- Объясняйте «почему»: вместо «это неправильно» напишите «здесь может быть утечка памяти, потому что
Rcсоздаёт циклическую ссылку. Попробуйте использоватьWeak». - Предлагайте альтернативы: если вы видите проблему, предложите конкретное решение. Например, «вместо
unwrap()лучше использовать?оператор, чтобы ошибка пробрасывалась наверх». - Хвалите хороший код: отмечайте удачные решения, например, «отличное использование
matchдля обработки всех вариантов». - Избегайте абсолютных утверждений: вместо «всегда используй
?