Rust давно перестал быть языком энтузиастов. На нём собраны куски ядра Linux, движки баз данных и аналитики (TiKV, Materialize, Polars), бэкенды Cloudflare и Discord. Под Rust пишут прошивки для ESP32 и STM32, фронтенд через WebAssembly, инференс LLM.
Microsoft переписывает части Windows, AWS строит на Rust Firecracker и Bottlerocket, Google пускает его в Android и в дерево ядра. По зарплатам Rust пятый год держится в верхнем дециле Stack Overflow Survey, и семь лет подряд – самый любимый язык разработчиков.
Я веду github.com/Develp10/rust-roadmap-ru – живую карту того, что и в каком порядке учить. Эта статья – её расширенный текстовый вариант с примерами, ссылками и личным опытом.
Что внутри
-
12 этапов roadmap’а от настройки окружения до уровня профи
-
До коммита в rustc: путь до контрибьютора компилятора
-
Crate-замены привычных инструментов для тех, кто переходит с Python/Node/Go
Карта по уровням
|
Уровень |
Что умеешь |
Сколько обычно занимает |
|---|---|---|
|
Новичок |
Синтаксис, ownership на интуиции, простые консольные программы |
1-3 месяца |
|
Уверенный |
Generics, traits, обработка ошибок, тесты, async на уровне axum/tokio |
6-12 месяцев |
|
Middle |
Свои библиотеки, многопоточка без багов, понимание lifetimes, чужой код читаешь |
1-2 года с коммерческим проектом, 2-3 года на самообучении |
|
Senior |
Unsafe осознанно, FFI, макросы, оптимизация под кеш, debugging async-зависаний |
2-4 года в production, у самоучек 4+ |
|
Профи |
Контрибьюты в tokio/serde/rustc, предсказываешь поведение borrow checker, понимаешь модель памяти и MIR |
5+ лет, и не у всех получается |
Цифры справа – медиана по моим знакомым и опросам в чатах, не гарантия. Кто-то с сильным C+±бэкграундом проходит путь до Middle за 8 месяцев, кто-то застревает на ownership на год – и это нормально.
Как пользоваться этой картой
Три правила:
-
Не торопись. Этапы 2, 7 и 9 – переломные. Без них следующие просто не лягут.
-
Перепрыгивать можно, но возвращаться придётся. Если читал про async раньше, чем разобрался с ownership – почти наверняка вернёшься назад. Это бесплатный совет, который я выучил дорогой ценой.
-
Контрольные точки честные. Если не можешь объяснить пример из контрольной – этап не пройден, как бы ни хотелось двигаться дальше.
Что Rust решает
Один пример вместо лекции. Вот фрагмент на C++:
std::vector<int> v = {1, 2, 3};
int& r = v[0];
v.push_back(4); // вектор может перевыделить память
std::cout << r; // r теперь висячая ссылка, UB
То же самое на Rust компилятор остановит ещё до запуска:
let mut v = vec![1, 2, 3];
let r = &v[0];
v.push(4); // ошибка: cannot borrow `v` as mutable because it is also borrowed as immutable
println!("{}", r);
Это и есть продажа Rust в одном слайде: целый класс багов, на которые в C/C++ уходят дни отладки и которые регулярно становятся CVE, в Rust превращается в ошибку компиляции. Не «безопасный язык вообще», а конкретно отсутствие data races и use-after-free без GC.
Borrow checker не учит писать Rust. Он учит думать о владении данными, и эта привычка остаётся в любом языке, который ты возьмёшь потом.
Второй уровень – производительность. Zero-cost abstractions значат, что итераторы, traits и async компилируются в такой же машинный код, как ручной цикл на C. Третий – экономика. Серверная аренда дорогая, энергопотребление считают, и компании мигрируют горячие пути с Python и Java на Rust ради уменьшения парка машин в разы.
Это не теория: Discord переписал Read States с Go на Rust и убрал пики GC, Cloudflare на Rust пишет Pingora – прокси, через который идёт значительная часть мирового HTTP-трафика. Это другой класс надёжности.
Когда брать Rust, а когда нет
Самое честное, что можно сказать новичку: Rust – не лучший выбор для большинства задач. Он лучший для задач, где цена ошибки высока, а ресурсы ограничены.
|
Задача |
Брать Rust? |
Чем заменить, если нет |
|---|---|---|
|
Высоконагруженный сетевой сервис |
Да |
Go (проще для команды), Java/Kotlin (есть экспертиза) |
|
Скрипт автоматизации, ETL на день |
Нет |
Python, Bash |
|
Прошивка для микроконтроллера |
Да |
C (если жёсткие требования к toolchain) |
|
Веб-фронтенд |
Только через WASM для тяжёлых вычислений |
TypeScript |
|
Прототип ML-модели |
Нет |
Python + PyTorch |
|
Инференс модели в продакшене |
Да, если важна латентность |
C++, ONNX Runtime |
|
CLI-утилита для дистрибуции |
Да |
Go |
|
Десктоп-приложение |
Да, через Tauri, если важен размер |
Electron, Qt, Flutter |
|
Игровой движок |
Зрелые альтернативы важнее |
C++ (Unreal), C# (Unity), Godot |
|
CRUD с дедлайном через неделю |
Нет |
то, что знает команда |
|
Парсер с гарантиями корректности |
Да |
OCaml, Haskell |
|
Криптография в продакшене |
Да |
Go, C |
|
Обработка финансовых транзакций |
Да |
Java, C++ (по требованиям compliance) |
Если в твоём случае Rust «можно, но не обязательно» – бери то, что знает команда. Rust окупается на горизонте полугода и больше.
Быстрый старт: первый месяц
Не пытайся прочитать The Rust Book целиком и параллельно Rustlings и параллельно курсы. Это рецепт выгорания. Лучше так:
-
неделя 1: главы 1-6 The Rust Book + первые 30 упражнений Rustlings;
-
неделя 2: главы 7-10 + написать CLI-утилиту на 200 строк (грабер RSS или подсчёт строк в директории);
-
неделя 3: главы 11-13 + переписать одну свою старую утилиту с Python/Go на Rust и сравнить;
-
неделя 4: главы 14-17 + начать первый «настоящий» проект (см. чек-лист в конце).
К концу месяца у тебя в портфолио должен быть один проект, на который не стыдно дать ссылку. Без своего проекта Rust в голове не закрепляется, и туториалы создают ложное чувство уверенности.
Часть 1. Roadmap по этапам
Этапы 0-2 – фундамент языка. Этапы 3-6 – язык в production. Этапы 7-9 – глубина. Этапы 10-11 – выход в индустрию.
Этап 0. Настройка окружения – фундамент, без которого всё сыпется
Что ставим
-
rustup – менеджер тулчейнов. Никогда не ставь rustc через системный пакетный менеджер;
-
VS Code + rust-analyzer или RustRover от JetBrains. rust-analyzer бесплатный и почти не уступает;
-
cargo-edit, cargo-watch, bacon для удобной разработки;
-
nightly-канал для экспериментов:
rustup toolchain install nightly.
Минимальный шаблон проекта
Создай и сохрани себе .cargo/config.toml с быстрым линкером и шаблон Cargo.toml с твоими привычными зависимостями:
# .cargo/config.toml
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
[alias]
b = "build"
c = "check"
t = "test"
r = "run"
Зачем это всё
Большинство «странных» проблем у новичков – не Rust, а сломанный rustup, конфликт toolchain’ов или старый rust-analyzer. Один день на нормальную настройку экономит месяц мучений.
Этап 1. Базовый синтаксис – привыкаешь к новому языку
Что учить
Переменные, типы, control flow, функции, базовые коллекции (Vec, String, HashMap), модули. Это 1-2 недели для человека, который уже знает любой системный язык, и 3-4 недели для пришедших из Python/JS.
Где ломаются
На String vs &str. Это первое столкновение с системой типов Rust: одна и та же «строка» имеет минимум два представления, и компилятор требует осознанного выбора. Не воспринимай это как раздражение – это лучшая тренировка перед ownership.
Первый код, который должен работать
fn greet(name: &str) -> String {
format!("Привет, {}!", name)
}
fn main() {
let name = String::from("мир");
println!("{}", greet(&name));
// name всё ещё валиден - мы передали ссылку, не владение
}
Если ты понимаешь, почему здесь работает &name и что было бы, если передать просто name – этап 1 пройден.
Проект этапа
CLI-калькулятор или конвертер единиц. 100-200 строк, без external crates.
Этап 2. Владение, заимствование, времена жизни – здесь сломается большинство
Что учить
Ownership, borrowing, &T vs &mut T, lifetimes, перемещение значений, Copy vs Clone. Главы 4 и 10 The Rust Book + раздел про lifetimes в Rust by Example.
Где ломаются
Это самая сложная и самая важная глава Rust. На этом этапе случается момент: «я не понимаю, почему компилятор ругается, и я устал». Это нормально.
Главная ошибка – бороться с borrow checker’ом, добавляя .clone() везде. Работает, но Rust теряет смысл. Правильнее остановиться и переосмыслить структуру данных.
Проект этапа
Реализуй упрощённый Vec<T> или односвязный список. Это классический тест: если ты можешь написать односвязный список на Rust без подсказок – первый барьер пройден. У Aria Beingessner есть знаменитая статья «Learn Rust With Entirely Too Many Linked Lists» – проходи параллельно.
Контрольная точка после этапа 2
Объясни, почему этот код не компилируется, и предложи три способа починки:
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
}
Можешь – двигайся дальше. Нет – возвращайся к главе 4 The Rust Book. В спешке этот этап не проходится.
Этап 3. Структуры данных и абстракции – складываешь конструктор
Что учить
struct, enum, impl, методы, ассоциированные функции, traits, generics, trait bounds. The Rust Book главы 5, 10. Параллельно: Rust API Guidelines – как принято писать публичные API.
Generic-функция с trait bounds
use std::fmt::Display;
fn longest<'a, T: Display>(items: &'a [T]) -> Option<&'a T> {
items.iter().max_by_key(|item| item.to_string().len())
}
fn main() {
let words = vec!["короткое", "длинноватое", "среднее"];
if let Some(w) = longest(&words) {
println!("самое длинное: {}", w);
}
}
Здесь T: Display – trait bound, 'a – lifetime, и обе вещи становятся естественными к концу этого этапа.
Где ломаются
На trait bounds сложнее T: Clone + Send. Когда появляются ассоциированные типы, blanket impls, where-clauses – это первый намёк на устройство стандартной библиотеки. В production-коде такое встречается редко.
Проект этапа
Мини-ORM-like билдер запросов или конвертер форматов (JSON ↔ TOML ↔ YAML) с собственными trait-абстракциями.
Этап 4. Обработка ошибок и тестирование – делаешь код, который не стыдно показать
Что учить
Result<T, E>, Option<T>, оператор ?, thiserror для библиотек, anyhow для приложений, #[test], cargo test, proptest и insta для серьёзных проверок. Хороший разбор: Error Handling in Rust by BurntSushi.
Три стратегии работы с ошибками
// 1. Для прототипов: Box<dyn Error> - быстро, но без типизации
fn quick(path: &str) -> Result<String, Box<dyn std::error::Error>> {
Ok(std::fs::read_to_string(path)?)
}
// 2. Для приложений: anyhow - удобный контекст, без типизации ошибок
fn app(path: &str) -> anyhow::Result<String> {
use anyhow::Context;
std::fs::read_to_string(path)
.with_context(|| format!("не смог прочитать {}", path))
}
// 3. Для библиотек: thiserror - типизированные ошибки для потребителей
#[derive(thiserror::Error, Debug)]
pub enum ConfigError {
#[error("файл {0} не найден")]
NotFound(String),
#[error("невалидный TOML: {0}")]
Parse(#[from] toml::de::Error),
}
Личное наблюдение
В первых проектах все суют anyhow везде – ? с ним работает магически, и это нормальный старт. Но как только пишешь библиотеку, которой будут пользоваться другие – переходи на thiserror. Твои ошибки должны быть типизированными, не строковыми.
Проект этапа
Возьми CLI-утилиту с этапа 2 и переработай: добавь свои error-типы через thiserror, unit-тесты, integration-тесты, property-based тесты для одной критичной функции. Заведи CI на GitHub Actions с cargo fmt, cargo clippy -- -D warnings и cargo test.
Этап 5. Умные указатели и интериор-мутабельность – перестаёшь бояться Arc
Что учить
Box<T>, Rc<T>, Arc<T>, RefCell<T>, Cell<T>, Mutex<T>, RwLock<T>, Cow<T>. Когда какой использовать и почему. The Rust Book главы 15-16. Дополнительно – The Rustonomicon для тех, кто хочет понять внутренности.
Пример «до/после»
Типичная история: новичок пишет дерево через Box<Node> и упирается в то, что у узла не может быть нескольких родителей. Решение – переход к Rc<RefCell<Node>> для дерева в одном потоке или к Arc<Mutex<Node>> для многопоточного случая. Становится ясно, зачем эти типы вообще нужны и почему их нельзя смешивать как попало.
use std::rc::Rc;
use std::cell::RefCell;
type NodeRef = Rc<RefCell<Node>>;
struct Node {
value: i32,
children: Vec<NodeRef>,
parent: Option<NodeRef>,
}
Проект этапа
Графовая структура с обходом в ширину и в глубину. Сначала на Vec<Vec<usize>> (adjacency list – чаще всего этого хватает), потом на Rc<RefCell> со взаимными ссылками. Разница в сложности станет очевидной.
Этап 6. Многопоточность – параллелизм, который компилируется или не падает
Что учить
std::thread, std::sync (Mutex, RwLock, Arc, Barrier, Condvar), crossbeam для каналов и эпохального GC, rayon для параллельных итераторов, parking_lot для быстрых мьютексов. Trait’ы Send и Sync, что они в действительности означают.
Главная мысль этапа
Rust не делает многопоточку быстрее. Он делает её корректнее. Data race – это compile error.
Это меняет процесс разработки: вместо «запустил, увидел рандомный краш через 10 минут» получаешь «не скомпилировалось, потому что shared mutable state без синхронизации».
Пример
use std::sync::{Arc, Mutex};
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
let mut n = c.lock().unwrap();
*n += 1;
}));
}
for h in handles { h.join().unwrap(); }
println!("{}", *counter.lock().unwrap()); // всегда 10
Проект этапа
Параллельный word-counter для больших файлов через rayon, потом thread pool на каналах через crossbeam. Сравни с однопоточной версией на гигабайтном файле – почувствуешь, ради чего всё это.
Этап 7. Асинхронное программирование – где живёт большинство production-багов
Что учить
async/await, tokio как стандарт de facto, axum для HTTP-серверов, reqwest для клиентов, sqlx или sea-orm для БД. Tokio Tutorial – лучший вход.
С 1.75 (декабрь 2023) async fn можно объявлять в трейтах напрямую, но с оговорками: для dyn Trait это работает иначе, для Send-границ нужен атрибут #[trait_variant::make(Send)] или старый крейт async-trait (в библиотеках он остаётся стандартом). Место, где новички спотыкаются регулярно.
Cancellation safety и structured concurrency
Главная подстава async-Rust для пришедших из Go и JS – cancellation. Future в Rust можно отменить в любой await-точке. Если внутри select! твой код держит частично записанное состояние – получишь corrupted state без всякого паники.
Помогает дисциплина: для одновременного запуска задач предпочитай tokio::JoinSet вместо ручного spawn + сборки хендлов, для отмены – CancellationToken из tokio-util, для select – проверяй, что каждая ветка cancellation-safe (это явно указано в документации tokio для большинства async-методов).
use tokio::task::JoinSet;
let mut set = JoinSet::new();
for url in urls {
set.spawn(fetch(url));
}
while let Some(res) = set.join_next().await {
// обрабатываем результат, при падении одной - остальные продолжают
}
Graceful shutdown
Сервис должен уметь завершаться без потерь in-flight запросов. Базовый паттерн:
use tokio::signal;
use tokio_util::sync::CancellationToken;
let token = CancellationToken::new();
let child = token.child_token();
let server = tokio::spawn(async move {
run_server(child).await
});
signal::ctrl_c().await.unwrap();
println!("получен SIGINT, завершаемся");
token.cancel();
server.await.unwrap();
Это вопрос на любом интервью на middle+. Готовь паттерн заранее.
Tracing – без него production невозможен
В синхронном Rust ты можешь дебажить println’ами. В async – нет: задачи переключаются между потоками, стек не поможет. Ставь tracing и tracing-subscriber сразу при создании проекта, добавляй #[tracing::instrument] на все async-функции, выводи в JSON для прода. Это обязательная часть инфраструктуры, не «когда-нибудь потом».
Проект этапа
HTTP-сервис на axum: эндпоинт, который ходит во внешний API, кеширует ответы в Redis, пишет в Postgres через sqlx. Добавь graceful shutdown, structured logging через tracing, метрики через metrics, интеграционные тесты с testcontainers.
Контрольная точка после этапа 7
Сделай pet-проект на 500-1500 строк, который реально работает на сервере хотя бы неделю. Сервис-сокращатель ссылок, бот в Telegram, прокси с rate limiting – что угодно. Можешь поддерживать его и расширять без переписывания с нуля – переходи к следующим этапам.
Этап 8. Макросы и метапрограммирование – расширяешь сам язык
Что учить
Декларативные макросы (macro_rules!), процедурные макросы трёх видов (derive, attribute, function-like), крейты syn и quote. Книга-эталон – «The Little Book of Rust Macros».
Простой macro_rules – с него начинают все
macro_rules! hashmap {
($($key:expr => $val:expr),* $(,)?) => {{
let mut m = std::collections::HashMap::new();
$( m.insert($key, $val); )*
m
}};
}
fn main() {
let m = hashmap! {
"one" => 1,
"two" => 2,
};
println!("{:?}", m);
}
90% макросов в кодовой базе – именно такие. Они полностью покрывают потребность в DSL без захода в proc-macros.
Личное наблюдение
Не пиши процедурные макросы, пока действительно не понадобятся. Когда дойдёшь – сначала смотри готовые крейты: darling для парсинга атрибутов сильно упрощает жизнь, и почти всегда подключай syn с фичей full – без неё парсинг сложных конструкций ломается на неочевидных местах.
Где это нужно
Если используешь #[derive(Serialize, Deserialize)] из serde – ты уже зависишь от proc-macros. Свои писать нужно для DSL внутри фреймворка или для устранения boilerplate в больших проектах.
Проект этапа
Реализуй простой derive-макрос: #[derive(Builder)], который генерирует builder-паттерн для структуры. Это классическое упражнение и хороший вход в мир syn/quote.
Этап 9. Unsafe Rust и FFI – спускаешься в подвал
Что учить
Что можно делать в unsafe-блоке (всего пять операций), The Rustonomicon, FFI с C через extern "C", #[repr(C)], биндинги через bindgen и cbindgen. Понятие undefined behavior и почему оно опаснее обычного бага.
Главная мысль про unsafe
unsafe– не «выключить безопасность». Это контракт: инварианты, которые обычно проверяет компилятор, ты гарантируешь сам.
Стандартная библиотека внутри полна unsafe-кода, но он завёрнут в безопасные интерфейсы.
Как правильно оформлять unsafe-блок
/// # Safety
/// Указатель ptr должен быть валидным, выровнен на T и
/// указывать на инициализированное значение, владение которым
/// принадлежит вызывающей стороне.
unsafe fn read_owned<T>(ptr: *mut T) -> T {
// SAFETY: контракт гарантирует валидность и владение.
// Дублирование запрещено: ptr нельзя использовать после этого вызова.
std::ptr::read(ptr)
}
Два правила, которые делают unsafe-код поддерживаемым: # Safety секция в doc-комментарии и SAFETY: комментарий перед каждым unsafe-блоком, где явно сказано, какой именно инвариант гарантирован.
Soundness – концепт, который надо понять
Sound API – такой, где никакая комбинация безопасных вызовов не приводит к UB. Если кто-то может вызвать твою библиотеку без unsafe и получить use-after-free – твоя библиотека unsound. Это не «бэйджик за качество», это базовое требование к публичной API. Когда такое находят в популярных крейтах – выпускают yanked-версию и пишут постмортем.
Полезные инструменты
-
miri – интерпретатор MIR, ловит UB в unsafe-коде (
cargo +nightly miri test); -
loom – тестирование concurrent-кода с перебором interleavings;
-
cargo-fuzz для fuzz-тестирования с libFuzzer;
-
Address Sanitizer для отладки FFI-кода.
Проект этапа
Сделай safe-обёртку над какой-то C-библиотекой (zlib, libcurl, что-то простое). Полноценное упражнение на FFI плюс осознание того, чем «safe» отличается от «не падает на твоих тестах».
Этап 10. Экосистема и реальные проекты – выходишь в open source
Что учить
-
сборка и публикация крейтов:
cargo publish, версионирование, semver; -
workspaces для многокрейтных репозиториев;
-
инфраструктура зрелого проекта: cargo-deny (политики зависимостей и лицензий), cargo-audit (проверка CVE), cargo-machete (поиск неиспользуемых зависимостей), cargo-nextest (быстрый тест-раннер);
-
бенчмаркинг через criterion;
-
кросс-компиляция через cross;
-
профилирование – flamegraph, perf, samply.
Минимальный CI для крейта на crates.io
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with: { components: rustfmt, clippy }
- run: cargo fmt --check
- run: cargo clippy -- -D warnings
- run: cargo test --all-features
С этим минимумом твой крейт уже выглядит профессионально.
Где брать первый open source-опыт
This Week in Rust ведёт раздел «Call for Participation», там еженедельно публикуют issue с меткой «good first issue» из больших проектов. Хороший заход – найти проект, которым ты сам пользуешься, и закрыть один баг или улучшить документацию. Контрибьюторы крупных крейтов почти всегда отвечают доброжелательно.
Проект этапа
Опубликуй свой первый крейт. Не обязательно революционный – утилита для конкретной узкой задачи, которой пользуешься сам. Цикл от cargo new до cargo publish нужно пройти руками.
Этап 11. Уровень профи – то, что отделяет senior от middle
Что учить
-
глубокая типовая магия: HRTB, GAT (generic associated types), type-level programming через типажи-маркеры;
-
variance и
PhantomData– зачем они и когда нужны; -
const generics в production-сценариях (массивы, размерности тензоров);
-
понимание borrow checker до уровня intuition – предсказываешь ошибки до компиляции;
-
MIR и оптимизации компилятора – Rust Compiler Development Guide;
-
модель памяти Rust (пока формально не зафиксирована, но есть aliasing model Stacked Borrows / Tree Borrows);
-
продвинутые async-паттерны: pinning, собственные Future, runtime-агностичные библиотеки.
GAT – пример того, что появляется только на этом уровне
Generic associated types (стабилизированы в Rust 1.65) позволяют параметризовать ассоциированные типы трейтов. Самый понятный сценарий – lending iterator: итератор, который выдаёт ссылки на свой внутренний буфер.
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next(&mut self) -> Option<Self::Item<'_>>;
}
До GAT такое было невыразимо в Rust без обходных манёвров. Если понимаешь, зачем здесь Item<'a> и почему нужен where Self: 'a – ты на этом уровне.
HRTB – higher-ranked trait bounds
for<'a> нужен, когда замыкание должно работать с любым lifetime, а не с конкретным. Классический пример:
fn apply<F>(f: F) where F: for<'a> Fn(&'a str) -> &'a str {
let s = String::from("hello");
println!("{}", f(&s));
}
Без for<'a> компилятор зафиксирует один конкретный lifetime, и более общие замыкания не подойдут.
Variance в одном предложении
Variance определяет, как параметризованный тип «наследует» отношения подтипирования своих параметров. На практике это всплывает в FFI и собственных smart-pointer’ах – там без PhantomData<T>, PhantomData<fn() -> T> или PhantomData<*const T> поведение borrow checker’а становится неинтуитивным.
Что должно быть в голове
В этой точке ты умеешь читать сложные ошибки borrow checker’а и быстро понимать, где компилятор прав, а где можно перестроить код. На реальных интервью в senior+ роли этот навык проверяют живыми задачами.
Контрольная точка после этапа 11
Можешь объяснить, почему Pin нужен для самореферентных Future, без обращения к документации. Знаешь разницу между Send и Sync на уровне «какой инвариант обеспечивает каждый». Хотя бы раз сделал контрибьют в популярный крейт уровня tokio/serde/clap, и он был принят.
Частые ошибки новичков
Грабли, которые я наблюдаю годами в чатах и pull request’ах:
-
Переписывание Python/JS-кода один-в-один. Структуры данных в этих языках построены на shared mutable state. В Rust такой код заставит обмазать всё
Rc<RefCell>илиArc<Mutex>и потерять весь смысл языка. Сначала переосмысли структуру: где данные живут, кто ими владеет, кто читает. -
.clone()как способ заткнуть компилятор. Работает, но скрывает проблему дизайна. Если клонируешь большую структуру в цикле – почти наверняка можно передать ссылку. Если приходится клонироватьStringв каждой итерации – подумай проCow<str>. -
unwrap()в production-коде. Для прототипа нормально, для прода – нет. Замени на?с понятным error-типом либо наexpect("осмысленное сообщение")там, где panic действительно ожидаем. -
Избегание
unsafeлюбой ценой.unsafeне зло. Зло – unsound API, который снаружи выглядит безопасным. Иногда правильный путь – небольшой unsafe-блок с инвариантом в комментарии вместо громоздкой safe-обёртки. -
Преждевременная оптимизация на типах. Не пиши generic-функции с пятью trait bounds сразу. Сначала конкретные типы, потом, когда виден паттерн – generic.
-
Игнор clippy. Включи
cargo clippy -- -D warningsв CI с самого начала. Clippy ловит десятки антипаттернов, которые иначе остаются в кодовой базе. -
Зависимости без меры.
cargo addставится за секунду, но каждая зависимость – это время компиляции, поверхность атаки и потенциальный maintenance burden. На pet-проекте 10-15 зависимостей разумно, 100+ – повод задуматься.
До коммита в rustc
Самая высокая точка roadmap’а – попасть в команду компилятора. Не обязательно для карьеры, но лучшая школа, которую можно представить.
Путь обычно такой:
-
Стать активным контрибьютором в tokio, serde, rust-analyzer или cargo. Это уровень «senior+ в Rust».
-
Параллельно читать Rustc Dev Guide и пробовать собрать компилятор локально. Готовься: полная сборка занимает 30-90 минут на нормальной машине.
-
Найти E-easy issue в rust-lang/rust и сделать PR. Это занимает обычно несколько вечеров с непривычки.
-
После 3-5 принятых PR можно претендовать на статус reviewer в одной из команд (compiler, lang, libs).
Первый PR в rustc от issue до merge почти всегда занимает 2-4 недели. CI длинный, очереди ревью длинные, авторы перфекционисты. Это не отказ – это норма процесса.
Реалистичный срок до устойчивого контрибьюта – 2-4 года с момента, как начал писать на Rust серьёзно. У некоторых получается быстрее, у большинства не получается вовсе, и это нормально. Контрибьют в rustc не цель сам по себе.
Часть 2. Куда расти после roadmap
После того как этапы 0-11 пройдены, варианты ветвления:
-
Systems programming. Ядро Linux (Rust-for-Linux уже в апстриме), eBPF, гипервизоры, файловые системы. Самая «классическая» ниша.
-
Embedded и IoT. No-std, embedded-hal, RTIC, embassy для async на микроконтроллерах. Хороший вход – Embedded Rust Book.
-
WebAssembly. wasm-bindgen, Yew/Leptos/Dioxus для фронтенда, WASI для server-side WASM. Здесь Rust сейчас лидер по экосистеме.
-
Базы данных и big data. TiKV, Materialize, Polars, DataFusion, InfluxDB. Полно вакансий и интересных задач.
-
Криптография и блокчейн. Solana, Polkadot, многие L2-проекты на Ethereum. Платит хорошо, требует осторожности с выбором работодателя.
-
Compiler/language design. Rustc, Cranelift, разработка собственных языков на Rust.
-
DevOps-тулинг. Vector, OpenTelemetry, sccache – инструменты, которые ставятся миллионами.
-
AI/ML инфраструктура. candle, burn, tokenizers от HuggingFace – быстрорастущая область.
Не нужно выбирать всё. Хватит одной-двух ниш, в которых ты глубже середняка.
Слабые места Rust, о которых редко говорят
Маркетинговые статьи рассказывают про zero-cost abstractions и memory safety. Вот обратная сторона.
Технические
-
Долгая компиляция. На большом проекте полный билд может занимать 5-15 минут, инкрементальные сборки – 30-90 секунд. Помогают workspaces, sccache, отключение лишних фич, mold как линкер. Проблема остаётся.
-
Async-сложность. Pin, Future, ручная реализация runtime, cancellation safety – самые тяжёлые темы в языке. Многие senior-разработчики на Rust не пишут свои Future руками за всю карьеру.
-
GUI-фреймворки незрелые. egui, iced, slint, Tauri – все они либо нишевые, либо в активной разработке. До уровня Qt и Flutter им далеко.
-
Game dev в начале пути. Bevy красивый и быстро развивается, но индустрия пока на Unreal и Unity. Брать Rust первым языком для game dev – спорное решение.
-
Rust Edition. Edition (2015/2018/2021/2024) – снимки синтаксиса и небольших правил, которые backward-compatible: код на разных edition в одном проекте дружит, при апдейте нужен
cargo fix --edition. Иногда подкидывает сюрпризов в legacy-проектах.
Рыночные
-
Сложность найма. Rust-разработчиков мало, и хороший Rust-разработчик стоит дорого. Это плюс для того, кто его учит, и минус для компании, которая внедряет.
-
Документация неравномерна. Стандартная библиотека и популярные крейты документированы отлично. Но как только попадаешь в среднестатистический крейт – можешь обнаружить README на одну страницу и ничего больше.
-
Высокий порог входа. Не миф. От «знаю синтаксис» до «пишу production-код уверенно» проходит 6-18 месяцев активной работы. Не у всех есть это время.
Это не аргументы против Rust. Это аргументы против иллюзий.
Crate-замены привычных инструментов
Если приходишь из Python, Node или Go – вот шпаргалка по экосистеме:
|
Привычный инструмент |
Замена в Rust |
Комментарий |
|---|---|---|
|
requests (Python) |
reqwest |
API близкое, async и sync режимы |
|
httpx |
reqwest |
+ ручной |
|
pandas |
Часто быстрее pandas в 5-30 раз |
|
|
numpy |
Менее эргономичный, но рабочий |
|
|
FastAPI / Flask |
Стандарт нового кода на async |
|
|
Django |
Молодой, но самый «бэттериз-инклудед» |
|
|
pytest |
Встроено в |
|
|
SQLAlchemy |
sqlx проверяет SQL на этапе компиляции |
|
|
Celery |
Молодая ниша, рабочая |
|
|
express (Node) |
axum, actix-web |
Actix исторически быстрее, axum популярнее |
|
Socket.IO |
WebSocket стандартно |
|
|
Redis client |
fred моложе, удобнее для cluster |
|
|
Kafka client |
Биндинги к librdkafka, стабильно |
|
|
gRPC |
От авторов tokio, де-факто стандарт |
|
|
logrus / pino |
Не просто логи, а структурированная трассировка |
|
|
Cobra (Go) |
Лучший CLI-парсер в индустрии, без преувеличения |
|
|
Docker SDK |
Полное API Docker |
|
|
boto3 (AWS) |
Официальный SDK, в стабильной фазе |
Rust и AI-инструменты в 2026
LLM-помощники сильно изменили процесс разработки на Rust за последние два года. Картина по моему опыту такая:
-
Где помогают. Boilerplate, генерация
implстандартных трейтов, преобразование данных между форматами, написание тестов, подсказки по стандартной библиотеке, миграции между версиями фреймворков. На задачах уровня «напиши axum-эндпоинт, который делает X» современные модели справляются уверенно. -
Где врут. Async-трейты, lifetimes сложнее одного параметра, неочевидные правила coherence для трейтов, новые фичи языка (GAT, async closures), макросы из малопопулярных крейтов. Модель уверенно пишет код, который не компилируется, и зачастую сама не может это починить с трёх попыток.
-
Что лучше работает. Современные большие модели (Claude, GPT, Gemini верхних линеек) заметно лучше справляются с Rust, чем линейки прошлого поколения. Но borrow checker всё ещё слабая зона: модель может предложить четыре варианта починки lifetime-ошибки, и три из них не компилируются.
IDE-агенты сильнее чатов
Cursor, Continue, Zed-агенты и rust-analyzer + LLM плагины помогают на Rust заметно лучше чатовых LLM. Причины две: они видят весь проект (а не один сниппет в окне чата) и читают вывод cargo check после каждой правки. Это закрывает главную слабость моделей на Rust – незнание точного API крейтов в твоей версии. К 2026 году это уже стандарт работы, а не экзотика.
Практический рецепт
Используй LLM как «junior, который пишет первый набросок», не как авторитет. Всегда запускай cargo check и cargo clippy на сгенерированном коде. Не доверяй объяснениям модели на тему, почему компилятор «должен» это пропустить.
В перспективе всё это будет улучшаться. Текущий вывод простой: Rust требует понимания, LLM не заменяет его, она ускоряет рутину.
Деньги: вилки зарплат и рынок
Оговорка: цифры ниже – усреднение по открытым вилкам, опросам Stack Overflow и публичным данным с конца 2024 – начала 2026. Конкретно у тебя может быть как лучше, так и хуже.
|
Регион |
Junior |
Middle |
Senior |
|---|---|---|---|
|
Россия (удалёнка) |
150-250k руб/мес |
300-500k руб/мес |
500-800k+ руб/мес |
|
Восточная Европа |
2-3k EUR/мес |
4-6k EUR/мес |
7-10k+ EUR/мес |
|
Западная Европа |
50-70k EUR/год |
80-120k EUR/год |
130-200k+ EUR/год |
|
США (remote, mid-market) |
110-140k USD/год |
150-200k USD/год |
220-350k+ USD/год |
|
США (Big Tech / crypto) |
редкий junior |
200-300k USD/год |
350-600k+ USD/год total comp |
Особенности рынка:
-
Junior-позиций мало. Большинство компаний хотят сразу Middle с самостоятельностью. Путь через pet-проекты и open source для Rust важнее, чем для других языков.
-
Крипто-проекты исторически платят верхнюю границу диапазонов, но риски (волатильность, остановки выплат, репутация) выше. Внимательно проверяй работодателя.
-
Embedded-Rust и core-инфраструктура часто платят меньше web-Rust, при этом задачи интереснее. Сознательный размен, на который многие идут.
-
Удалёнка для Rust остаётся нормой даже там, где общий рынок откатился к гибриду.
Будни Rust-разработчика
Хайп вокруг языка иногда создаёт впечатление, что Rust-разработчик каждый день пишет lock-free структуры данных и оптимизирует кеш-линии. Реальность скучнее.
Если ты работаешь в продуктовой компании, типичные задачи такие: новая ручка в HTTP-API, миграция схемы БД, рефакторинг старого модуля, починка флака в тестах, доработка retry-логики у внешнего API-клиента, обновление зависимостей. Технически это CRUD на axum + sqlx + tracing, с теми же бизнес-проблемами, что в Python или Go.
Где Rust заметно отличается:
-
Меньше runtime-инцидентов. То, что в Python ловтся мониторингом в проде, в Rust ловится
cargo check. Это снижает стресс. -
Код-ревью идут дольше. Borrow checker и типы заставляют ревьюера думать о владении данными – полезное замедление.
-
Зависимости обновляются осторожнее.
cargo updateна большом проекте может потянуть час разбирательств с breaking changes. -
Меньше «пятничных хотфиксов». В Rust сложнее быстро накатить горячую правку и удивиться поведению, поэтому культура чаще тяготеет к нормальному CI/CD.
Если идёшь в Rust ради хардкора каждый день – возможно, разочаруешься. Если идёшь ради меньшего количества боли в долгосрочной поддержке – попадёшь точно.
Как искать первую Rust-работу
Junior-вакансий на рынке мало, и стандартный путь «прислать резюме на 50 объявлений» в Rust работает плохо. Что работает:
-
Pet-проекты на GitHub важнее опыта. В резюме первая строка после контактов – ссылка на 2-3 ярких проекта. Они должны компилироваться с CI, иметь README с примером запуска и понятный код. Это закрывает 80% сомнений нанимающего.
-
Open source как лестница. Один принятый PR в популярный крейт (tokio, axum, clap) даёт больше веса, чем диплом. Hiring-менеджеры эти крейты знают.
-
Где смотреть вакансии: jobs.rust-lang.org, rustjobs.dev, раздел Jobs в This Week in Rust, GitHub Jobs (фильтр Rust), hh.ru и LinkedIn (по тегам Rust + tokio/axum/sqlx).
-
Стажировки и грантовые программы. Outreachy и Google Summer of Code регулярно берут проекты Rust-экосистемы. Это легальный путь к коммерческому опыту без коммерческого работодателя.
-
Конференции и митапы. RustConf, RustFest, локальные митапы. Половина первых офферов на Rust в чатах знакомых пришла через нетворкинг, не через резюме.
-
Фриланс через консалтинг. Mainmatter (бывшая Ferrous Systems), Tweede golf, Embecosm – примеры компаний, регулярно ищущих Rust-консультантов. Порог входа высокий, но это шанс начать с интересных проектов.
Главное: первый Rust-оффер обычно приходит дольше, чем первый Python- или Go-оффер. На это закладывайся.
Как устроены интервью на Rust в 2026
Структура обычная для индустрии, но с акцентами:
-
Скрининг. Лёгкая задача на алгоритмы + 2-3 вопроса по языку (ownership, traits, обработка ошибок).
-
Лайв-кодинг. Чаще всего просят написать что-то на 50-100 строк с использованием стандартной библиотеки. Главное – не идеальный код, а как ты рассуждаешь и реагируешь на ошибки компилятора.
-
Системный дизайн. Спрашивают про конкретные технологии: tokio, axum, sqlx. Готовься объяснять, почему выбираешь
Arc<Mutex>vs канал, как делаешь backpressure, как организуешь graceful shutdown. -
Глубокий разбор. Иногда дают код с багом и просят его найти. Классика – утечка
Arc-цикла, dead lock наMutex, неправильная cancellation safety вselect!. -
Поведенческое интервью. Стандартное, ничего специфичного для Rust.
Что спрашивают чаще всего: Send vs Sync, Box vs Rc vs Arc, ?Sized, как работает async fn, что такое Pin и зачем он нужен. На senior+ – модель памяти, оптимизации, профилирование.
Что готовить заранее: 1-2 своих проекта, про которые можешь рассказывать 20 минут с архитектурными решениями. Без этого пройти middle+ интервью почти невозможно.
Анти-FAQ
Самые частые вопросы от тех, кто думает, начинать ли:
-
Стоит ли учить Rust первым языком программирования? Скорее нет. Кривая обучения слишком крутая, и многие концепции (ownership, lifetimes) проще понимать после опыта с указателями в C или сборщиком мусора в Java/Python. Возьми Python или Go первым, через полгода-год переходи на Rust.
-
Стоит ли учить Rust после Python для бэкенда? Зависит от задач. Если у тебя CRUD без жёстких требований к латентности – Python остаётся продуктивнее. Если упираешься в производительность или хочешь снизить расходы на инфраструктуру – да, тогда Rust окупится.
-
Стоит ли учить Rust после C++? Скорее да. Это твой профильный язык будущего: базовые концепции ты уже понимаешь, остаётся принять borrow checker и async-модель. Многие C+±разработчики говорят, что Rust изменил их и C+±код в лучшую сторону.
-
Стоит ли учить Rust для game dev? Зависит от целей. Для коммерческой студии – нет, индустрия на Unreal и Unity. Для собственного движка или экспериментов с Bevy – почему бы и нет.
-
Стоит ли учить Rust для ML? Ядро ML остаётся на Python (PyTorch, JAX). Но инференс-инфраструктура, токенайзеры, сервинг моделей – всё чаще на Rust, и это растущая ниша.
-
Стоит ли учить Rust ради зарплаты? Стоит, но не как самоцель. Rust-вакансий мало, конкуренция за хорошие позиции жёсткая, junior-роли в дефиците. Если учишь только из-за денег – возможно, Go даст результат быстрее.
-
Сколько займёт стать продуктивным? До «могу писать рабочий код» – 2-3 месяца активной практики. До «беру с улицы middle-задачу и закрываю её» – 9-18 месяцев. До senior – годы.
Что почитать и посмотреть
С пометками от меня – что кому подойдёт.
Книги:
-
The Rust Programming Language – обязательно, бесплатно, идеальный первый шаг. Если ты прочитал её и понял главы 4 и 10 – дальше пойдёт легче.
-
Programming Rust (Blandy, Orendorff, Tindall) – более глубокий учебник, подходит тем, кто хочет понять «почему именно так». Стоит брать после Rust Book.
-
Rust for Rustaceans (Jon Gjengset) – для тех, кто уже пишет на Rust полгода и хочет дойти до senior. Не учебник, а сборник тем, которые редко проговаривают вслух.
-
Rust Atomics and Locks (Mara Bos) – бесплатно онлайн, лучшая книга про модель памяти и concurrency на Rust. Маст-рид перед серьёзной многопоточкой.
-
Zero to Production in Rust (Luca Palmieri) – проектно-ориентированная книга, ведёт от пустого репозитория до задеплоенного сервиса с CI, БД, тестами. Хороший практический материал после Rust Book.
Бесплатные онлайн-ресурсы:
-
Rust by Example – примеры кода для всех ключевых концепций.
-
Rustlings – упражнения для первого месяца.
-
The Rustonomicon – для тех, кто полез в unsafe.
-
Tokio Tutorial – лучший вход в async.
-
The Little Book of Rust Macros – макросы.
-
Comprehensive Rust – курс от Google.
YouTube-каналы:
-
Jon Gjengset – длинные стримы с разбором популярных крейтов изнутри. Самый качественный Rust-контент на YouTube.
-
Let’s Get Rusty – короткие туториалы, удобно для повторения.
-
No Boilerplate – идеи и обзоры, не учебный материал, но полезно для общего кругозора.
Рассылки и подкасты:
-
This Week in Rust – обязательная еженедельная рассылка.
-
Rustacean Station – подкаст с разработчиками экосистемы.
Исходники, которые стоит прочитать:
-
serde – чистая работа с traits и generics;
-
tokio – реальный async-runtime;
-
ripgrep – производительный CLI с продуманной архитектурой;
-
clap – эталон работы с procedural-макросами.
Где общаться: сообщество
Rust – один из самых здоровых tech-комьюнити в индустрии, и общение в нём заметно ускоряет обучение.
Международные ресурсы для общения:
-
r/rust – reddit-сообщество, отвечают на любые вопросы новичков.
-
users.rust-lang.org – форум для вопросов по языку.
-
internals.rust-lang.org – форум для обсуждения внутреннего устройства языка и компилятора.
-
Rust Zulip – официальный чат разработчиков языка. Здесь работают команды compiler/lang/libs.
-
Discord rust-lang – быстрые ответы по практическим вопросам.
-
Стэк Stack Overflow с тегом rust – архивная база ответов.
Русскоязычные:
Совет: задавай вопросы публично, даже если страшно. Хороший вопрос с минимальным воспроизводимым примером закроется за час, плохо сформулированный – не закроется никогда.
Чек-лист проектов для портфолио
К концу roadmap’а у тебя должны быть готовы 12 артефактов: настроенное окружение и 11 проектов.
-
Настроенный dev-env: rustup, rust-analyzer, шаблон
Cargo.tomlи.cargo/config.toml, готовый CI-workflow (этап 0). -
CLI-калькулятор или конвертер единиц (этап 1).
-
Свой
Vecили односвязный список (этап 2). -
Мини-ORM-билдер или конвертер форматов (этап 3).
-
CLI-утилита с тестами, CI и тип-обёрткой над ошибками (этап 4).
-
Графовая структура с обходами (этап 5).
-
Параллельный word-counter через rayon и crossbeam (этап 6).
-
HTTP-сервис на axum + Redis + Postgres с tracing (этап 7).
-
Derive-макрос (например, Builder) на
syn/quote(этап 8). -
Safe-обёртка над C-библиотекой через bindgen (этап 9).
-
Опубликованный крейт на crates.io (этап 10).
-
Реализация Future руками или контрибьют в популярный крейт (этап 11).
Это не «обязательная программа», а карта проверок. Если в портфолио чего-то нет – этого нет и в голове.
Куда идти прямо сейчас
Один следующий шаг, в зависимости от того, где ты находишься:
-
Никогда не писал на Rust. Открой The Rust Book и сделай первые два упражнения Rustlings. 30 минут сегодня.
-
Прошёл Rust Book, не знаешь, что делать. Напиши CLI-утилиту на 200-300 строк, которую сам будешь использовать.
-
Пишешь полгода, чувствуешь стагнацию. Возьми «Rust for Rustaceans» и tokio source. Будет тяжело и полезно.
-
Готовишься к интервью. Открой 2-3 публичные roadmap-задачи в Rust LeetCode-репозиториях, порешай по одной в день и параллельно пиши short-summary своих pet-проектов.
-
Хочешь open source. Раздел Call for Participation в This Week in Rust, выбери задачу с меткой good first issue в крейте, которым пользуешься. Закрой её до конца недели.
Rust не сделает тебя лучшим инженером сам по себе. Но он заставит думать о вещах, которые в других языках можно игнорировать годами – про владение данными, инварианты, границы ответственности модулей. Эта привычка остаётся в любом коде, который ты пишешь дальше.
Если roadmap зашёл – подписывайся на канал, посвященный Rust и кодингу, там обновления карты, разборы интервью и новые проекты. Если что-то пропустил или ошибся – пиши в комментариях, поправлю.
Спасибо, что дочитал! Замечания и советы по улучшению Роадмапа очень приветсвуются)
Автор: vibecodingai


