Отладка Rust кода: от «println!» до профи-инструментов
Каждый, кто писал на Rust хотя бы неделю, знает это чувство: компилятор пропустил, программа скомпилировалась, запускается… и делает что-то совершенно неожиданное. Или просто падает с загадочным Segmentation fault. Добро пожаловать в мир отладки! Хорошая новость: в Rust для этого есть целый арсенал — от простого макроса до продвинутых дебаггеров. В этой статье разберём все способы отладки Rust кода, от базовых до профессиональных.
1. Джентльменский набор: макросы dbg! и eprintln!
Начнём с самого простого и доступного. Если вы пишете Rust код и хотите быстро понять, что происходит в переменных — используйте dbg!. Он выводит и имя переменной, и её значение, и файл со строкой. Намного удобнее, чем старый добрый println!.
fn calculate_even_sum(numbers: &[i32]) -> i32 {
let mut sum = 0;
for &n in numbers {
if n % 2 == 0 {
sum += n;
dbg!(n, sum); // смотрим каждое чётное число и текущую сумму
}
}
sum
}
fn main() {
let data = vec![1, 2, 3, 4, 5, 6];
let result = calculate_even_sum(&data);
dbg!(result);
}
Запустите — и увидите что-то вроде:
[src/main.rs:6:13] n = 2
[src/main.rs:6:13] sum = 2
[src/main.rs:6:13] n = 4
[src/main.rs:6:13] sum = 6
[src/main.rs:6:13] n = 6
[src/main.rs:6:13] sum = 12
[src/main.rs:12:5] result = 12
А если нужно писать в stderr (например, чтобы не мешать stdout при пайпах) — используйте eprintln!. Это незаменимо при отладке Rust кода в продакшн-окружении.
2. Продвинутое логирование с log и env_logger
Когда проект растёт, раскидывать dbg! по всему коду становится больно. На помощь приходят крейты log и env_logger. Они позволяют включать/отключать логи без перекомпиляции.
use log::{info, warn, error, debug};
fn main() {
env_logger::init();
info!("Программа запущена");
let x = 42;
debug!("Значение x: {}", x);
if x > 100 {
warn!("x слишком большой!");
} else {
error!("Это не ошибка, просто проверка");
}
}
Запускайте с переменной окружения RUST_LOG=debug cargo run — и получите все логи. Хотите только предупреждения? RUST_LOG=warn. Очень удобно для отладки Rust приложений в реальном времени.
3. Паника и backtrace: читаем стек ошибок
Когда программа паникует, Rust выводит сообщение. Но часто этого мало. Включите полный backtrace:
$ RUST_BACKTRACE=1 cargo run
Или для максимальной детализации:
$ RUST_BACKTRACE=full cargo run
Вы увидите весь стек вызовов — от точки падения до main. Это критически важно при отладке Rust кода, если вы не понимаете, откуда взялась ошибка.
Пример: предположим, у вас есть такой код:
fn main() {
let v = vec![1, 2, 3];
println!("{}", v[10]); // паника!
}
С RUST_BACKTRACE=1 вы увидите не просто "index out of bounds", а точную строку и вызов.
4. Режим отладки и оптимизации: debug vs release
Важный момент: отладка Rust кода в режиме debug (по умолчанию) даёт полную информацию. Но в release компилятор оптимизирует код, и некоторые переменные могут исчезнуть или изменить порядок. Если вы отлаживаете «релизный» баг — используйте профиль с отладочной информацией:
[profile.release]
debug = true
В Cargo.toml. Это позволит вам запускать cargo run --release и всё равно видеть нормальные backtrace и переменные в дебаггере.
5. GDB и LLDB: отладка как в старые добрые времена
Если макросов и логов недостаточно (а рано или поздно станет недостаточно), пора переходить к настоящим дебаггерам. Rust отладчик на практике — это GDB (Linux) или LLDB (macOS/Linux). Rust компилируется в нативный код, поэтому работают стандартные инструменты.
Установите точки останова, смотрите переменные, шагайте по строкам:
$ rust-gdb target/debug/my_program
(gdb) break main
(gdb) run
(gdb) next
(gdb) print my_variable
(gdb) continue
Для LLDB команды похожи. Главное — собрать программу с отладочными символами (режим debug по умолчанию). Это мощный инструмент отладки Rust, который даёт полный контроль.
6. VS Code и rust-analyzer: визуальная отладка
Современные IDE делают отладку Rust кода почти как в Python или JavaScript. Установите расширение rust-analyzer и CodeLLDB (или Native Debug для GDB).
Теперь вы можете:
- Ставить точки останова кликом мыши
- Смотреть значения переменных в панели
- Шагать в функции, перешагивать, выходить
- Смотреть стек вызовов
Это настоящий дебаггер для Rust с графическим интерфейсом. Особенно полезно, если вы привыкли к визуальной отладке в других языках.
7. Анализ паники с human-panic
Для пользовательских приложений (не библиотек) полезен крейт human-panic. Он заменяет стандартное сообщение о панике на более дружелюбное и предлагает отправить отчёт.
use human_panic::setup_panic;
fn main() {
setup_panic!();
panic!("Ой, что-то пошло не так");
}
Вместо непонятного текста пользователь увидит что-то вроде: "Похоже, программа столкнулась с проблемой. Хотите помочь разработчикам? Отправьте отчёт." Это не совсем отладка Rust кода для разработчика, но полезно для с