От «Hello, World» до коммита в rustc: Roadmap Rust-разработчика на 2026 год. async.. async. ownership.. async. ownership. rust.. async. ownership. rust. tokio.. async. ownership. rust. tokio. асинхронность.. async. ownership. rust. tokio. асинхронность. карьера.. async. ownership. rust. tokio. асинхронность. карьера. Карьера в IT-индустрии.. async. ownership. rust. tokio. асинхронность. карьера. Карьера в IT-индустрии. Эдвард Де Боно. Серьёзное творческое мышление. Применение творческого мышления. Обучение.. async. ownership. rust. tokio. асинхронность. карьера. Карьера в IT-индустрии. Эдвард Де Боно. Серьёзное творческое мышление. Применение творческого мышления. Обучение. Программирование.. async. ownership. rust. tokio. асинхронность. карьера. Карьера в IT-индустрии. Эдвард Де Боно. Серьёзное творческое мышление. Применение творческого мышления. Обучение. Программирование. разработка.. async. ownership. rust. tokio. асинхронность. карьера. Карьера в IT-индустрии. Эдвард Де Боно. Серьёзное творческое мышление. Применение творческого мышления. Обучение. Программирование. разработка. Системное программирование.

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 – живую карту того, что и в каком порядке учить. Эта статья – её расширенный текстовый вариант с примерами, ссылками и личным опытом.

Что внутри

Карта по уровням

Уровень

Что умеешь

Сколько обычно занимает

Новичок

Синтаксис, 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’а – попасть в команду компилятора. Не обязательно для карьеры, но лучшая школа, которую можно представить.

Путь обычно такой:

  1. Стать активным контрибьютором в tokio, serde, rust-analyzer или cargo. Это уровень «senior+ в Rust».

  2. Параллельно читать Rustc Dev Guide и пробовать собрать компилятор локально. Готовься: полная сборка занимает 30-90 минут на нормальной машине.

  3. Найти E-easy issue в rust-lang/rust и сделать PR. Это занимает обычно несколько вечеров с непривычки.

  4. После 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

+ ручной hyper для тонкой настройки

pandas

polars

Часто быстрее pandas в 5-30 раз

numpy

ndarray

Менее эргономичный, но рабочий

FastAPI / Flask

axum

Стандарт нового кода на async

Django

loco

Молодой, но самый «бэттериз-инклудед»

pytest

#[test] + insta + proptest

Встроено в cargo test

SQLAlchemy

sqlx или sea-orm

sqlx проверяет SQL на этапе компиляции

Celery

apalis, faktory

Молодая ниша, рабочая

express (Node)

axum, actix-web

Actix исторически быстрее, axum популярнее

Socket.IO

tokio-tungstenite, axum-extra ws

WebSocket стандартно

Redis client

redis-rs, fred

fred моложе, удобнее для cluster

Kafka client

rdkafka

Биндинги к librdkafka, стабильно

gRPC

tonic

От авторов tokio, де-факто стандарт

logrus / pino

tracing

Не просто логи, а структурированная трассировка

Cobra (Go)

clap

Лучший CLI-парсер в индустрии, без преувеличения

Docker SDK

bollard

Полное API Docker

boto3 (AWS)

aws-sdk-rust

Официальный 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

Структура обычная для индустрии, но с акцентами:

  1. Скрининг. Лёгкая задача на алгоритмы + 2-3 вопроса по языку (ownership, traits, обработка ошибок).

  2. Лайв-кодинг. Чаще всего просят написать что-то на 50-100 строк с использованием стандартной библиотеки. Главное – не идеальный код, а как ты рассуждаешь и реагируешь на ошибки компилятора.

  3. Системный дизайн. Спрашивают про конкретные технологии: tokio, axum, sqlx. Готовься объяснять, почему выбираешь Arc<Mutex> vs канал, как делаешь backpressure, как организуешь graceful shutdown.

  4. Глубокий разбор. Иногда дают код с багом и просят его найти. Классика – утечка Arc-цикла, dead lock на Mutex, неправильная cancellation safety в select!.

  5. Поведенческое интервью. Стандартное, ничего специфичного для 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.

Бесплатные онлайн-ресурсы:

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 проектов.

  1. Настроенный dev-env: rustup, rust-analyzer, шаблон Cargo.toml и .cargo/config.toml, готовый CI-workflow (этап 0).

  2. CLI-калькулятор или конвертер единиц (этап 1).

  3. Свой Vec или односвязный список (этап 2).

  4. Мини-ORM-билдер или конвертер форматов (этап 3).

  5. CLI-утилита с тестами, CI и тип-обёрткой над ошибками (этап 4).

  6. Графовая структура с обходами (этап 5).

  7. Параллельный word-counter через rayon и crossbeam (этап 6).

  8. HTTP-сервис на axum + Redis + Postgres с tracing (этап 7).

  9. Derive-макрос (например, Builder) на syn/quote (этап 8).

  10. Safe-обёртка над C-библиотекой через bindgen (этап 9).

  11. Опубликованный крейт на crates.io (этап 10).

  12. Реализация 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

Источник