Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Хватит разговоров: покажите код

Что вы узнаете: вашу первую программу на Rust — fn main(), println!() и то, чем макросы Rust принципиально отличаются от препроцессорных макросов C/C++. К концу главы вы сможете написать, скомпилировать и запустить простые программы на Rust.

fn main() {
    println!("Hello world from Rust");
}
  • Этот синтаксис должен быть понятен всем, кто знаком с языками в стиле C
    • Все функции в Rust начинаются с ключевого слова fn
    • Точка входа по умолчанию для исполняемых файлов — main()
    • println! выглядит как функция, но на самом деле это макрос. Макросы в Rust сильно отличаются от препроцессорных макросов C/C++: они гигиеничны, типобезопасны и работают с синтаксическим деревом, а не с текстовой подстановкой
  • Два удобных способа быстро опробовать фрагменты кода на Rust:
    • Онлайн: Rust Playground — вставьте код, нажмите Run и поделитесь результатом. Установка не нужна
    • Локальный REPL: установите evcxr_repl для интерактивного REPL Rust (как REPL Python, только для Rust):
cargo install --locked evcxr_repl
evcxr   # Запустить REPL и вводить выражения Rust интерактивно

Локальная установка Rust

  • Rust можно установить локально одним из следующих способов
    • Windows: https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe
    • Linux / WSL: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • Экосистема Rust состоит из следующих компонентов
    • rustc — самостоятельный компилятор, но им редко пользуются напрямую
    • Основной инструмент — cargo, швейцарский армейский нож для управления зависимостями, сборки, тестирования, форматирования, линтинга и т. д.
    • Тулчейн Rust бывает в каналах stable, beta и nightly (экспериментальный), но мы будем использовать stable. Команда rustup update обновляет установку stable, которая выходит каждые шесть недель
  • Мы также установим плагин rust-analyzer для VSCode

Пакеты Rust (крейты)

  • Бинарные файлы Rust создаются из пакетов (далее — крейты)
    • Крейт может быть самостоятельным или зависеть от других крейтов. Крейты-зависимости могут быть локальными или удалёнными. Сторонние крейты обычно скачиваются из централизованного репозитория под названием crates.io.
    • Инструмент cargo автоматически загружает крейты и их зависимости. Концептуально это эквивалентно подключению C-библиотек
    • Зависимости крейта описываются в файле Cargo.toml. Там же задаётся тип цели для крейта: самостоятельный исполняемый файл, статическая библиотека, динамическая библиотека (встречается редко)
    • Справка: https://doc.rust-lang.org/cargo/reference/cargo-targets.html

Cargo и традиционные системы сборки C

Сравнение управления зависимостями

graph TD
    subgraph "Традиционный процесс сборки на C"
        CC["Исходные файлы C<br/>(.c, .h)"]
        CM["Ручной Makefile<br/>или CMake"]
        CL["Компоновщик"]
        CB["Итоговый бинарный файл"]
        
        CC --> CM
        CM --> CL
        CL --> CB
        
        CDep["Ручное управление<br/>зависимостями"]
        CLib1["libcurl-dev<br/>(apt install)"]
        CLib2["libjson-dev<br/>(apt install)"]
        CInc["Ручные пути включения<br/>-I/usr/include/curl"]
        CLink["Ручная компоновка<br/>-lcurl -ljson"]
        
        CDep --> CLib1
        CDep --> CLib2
        CLib1 --> CInc
        CLib2 --> CInc
        CInc --> CM
        CLink --> CL
        
        C_ISSUES["[ОШИБКА] Конфликты версий<br/>[ОШИБКА] Различия платформ<br/>[ОШИБКА] Отсутствующие зависимости<br/>[ОШИБКА] Важен порядок компоновки<br/>[ОШИБКА] Нет автоматических обновлений"]
    end
    
    subgraph "Процесс сборки Rust с Cargo"
        RS["Исходные файлы Rust<br/>(.rs)"]
        CT["Cargo.toml<br/>[dependencies]<br/>reqwest = '0.11'<br/>serde_json = '1.0'"]
        CRG["Система сборки Cargo"]
        RB["Итоговый бинарный файл"]
        
        RS --> CRG
        CT --> CRG
        CRG --> RB
        
        CRATES["crates.io<br/>(реестр пакетов)"]
        DEPS["Автоматическое разрешение<br/>зависимостей"]
        LOCK["Cargo.lock<br/>(фиксация версий)"]
        
        CRATES --> DEPS
        DEPS --> CRG
        CRG --> LOCK
        
        R_BENEFITS["[OK] Семантическое версионирование<br/>[OK] Автоматическая загрузка<br/>[OK] Кроссплатформенность<br/>[OK] Транзитивные зависимости<br/>[OK] Воспроизводимые сборки"]
    end
    
    style C_ISSUES fill:#ff6b6b,color:#000
    style R_BENEFITS fill:#91e5a3,color:#000
    style CM fill:#ffa07a,color:#000
    style CDep fill:#ffa07a,color:#000
    style CT fill:#91e5a3,color:#000
    style CRG fill:#91e5a3,color:#000
    style DEPS fill:#91e5a3,color:#000
    style CRATES fill:#91e5a3,color:#000

Структура проекта Cargo

my_project/
|-- Cargo.toml          # Конфигурация проекта (аналог package.json)
|-- Cargo.lock          # Точные версии зависимостей (генерируется автоматически)
|-- src/
|   |-- main.rs         # Главная точка входа для бинарного файла
|   |-- lib.rs          # Корень библиотеки (если создаёте библиотеку)
|   `-- bin/            # Дополнительные бинарные цели
|-- tests/              # Интеграционные тесты
|-- examples/           # Примеры кода
|-- benches/            # Бенчмарки
`-- target/             # Артефакты сборки (аналог build/ или obj/ в C)
    |-- debug/          # Отладочные сборки (быстрая компиляция, медленное выполнение)
    `-- release/        # Релизные сборки (медленная компиляция, быстрое выполнение)

Основные команды Cargo

graph LR
    subgraph "Жизненный цикл проекта"
        NEW["cargo new my_project<br/>[FOLDER] Создать проект"]
        CHECK["cargo check<br/>[SEARCH] Быстрая проверка синтаксиса"]
        BUILD["cargo build<br/>[BUILD] Скомпилировать проект"]
        RUN["cargo run<br/>[PLAY] Собрать и выполнить"]
        TEST["cargo test<br/>[TEST] Запустить все тесты"]
        
        NEW --> CHECK
        CHECK --> BUILD
        BUILD --> RUN
        BUILD --> TEST
    end
    
    subgraph "Дополнительные команды"
        UPDATE["cargo update<br/>[CHART] Обновить зависимости"]
        FORMAT["cargo fmt<br/>[SPARKLES] Форматировать код"]
        LINT["cargo clippy<br/>[WRENCH] Линтинг и подсказки"]
        DOC["cargo doc<br/>[BOOKS] Сгенерировать документацию"]
        PUBLISH["cargo publish<br/>[PACKAGE] Опубликовать на crates.io"]
    end
    
    subgraph "Профили сборки"
        DEBUG["cargo build<br/>(отладочный профиль)<br/>Быстрая компиляция<br/>Медленное выполнение<br/>Отладочные символы"]
        RELEASE["cargo build --release<br/>(релизный профиль)<br/>Медленная компиляция<br/>Быстрое выполнение<br/>Оптимизирован"]
    end
    
    style NEW fill:#a3d5ff,color:#000
    style CHECK fill:#91e5a3,color:#000
    style BUILD fill:#ffa07a,color:#000
    style RUN fill:#ffcc5c,color:#000
    style TEST fill:#c084fc,color:#000
    style DEBUG fill:#94a3b8,color:#000
    style RELEASE fill:#ef4444,color:#000

Пример: cargo и крейты

  • В этом примере у нас есть самостоятельный исполняемый крейт без других зависимостей
  • Используйте следующие команды, чтобы создать новый крейт под названием helloworld
cargo new helloworld
cd helloworld
cat Cargo.toml
  • По умолчанию cargo run скомпилирует и запустит debug-версию крейта (без оптимизаций). Чтобы запустить release-версию, используйте cargo run --release
  • Обратите внимание: сам бинарный файл находится в папке target, внутри папки debug или release
  • Возможно, вы также заметили файл Cargo.lock рядом с исходниками. Он генерируется автоматически и не должен редактироваться вручную
    • Конкретное назначение Cargo.lock мы рассмотрим позже