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

Основы Rust познакомили с синтаксисом Rust и основными концепциями. Теперь мы хотим пойти дальше: как эффективно использовать Rust в ваших проектах? Как выглядит идиоматичный Rust?

Этот курс имеет своё мнение: мы будем подталкивать вас к одним паттернам и отговаривать от других. Тем не менее мы понимаем, что у некоторых проектов могут быть другие потребности. Мы всегда приводим необходимую информацию, чтобы помочь вам принимать обоснованные решения в контексте и рамках ваших проектов.

⚠️ Этот курс находится в активной разработке.

Материалы могут часто меняться, и могут быть ошибки, которые ещё не заметили. Тем не менее мы призываем вас просмотреть их и дать ранний отзыв!

Расписание

Включая 10-минутные перерывы, это занятие займёт около 14 часов 10 минут. Оно включает:

СегментДлительность
Основы проектирования API3 часа 15 минут
Использование системы типов7 часов 30 минут
Полиморфизм3 часа 5 минут

Курс охватит перечисленные ниже темы. Каждая тема может быть раскрыта в одном или нескольких слайдах в зависимости от её сложности и значимости.

Целевая аудитория

Инженеры, имеющие не менее 2–3 лет опыта программирования на C, C++11 или новее, Java 7 или новее, Python 2 или 3, Go или любом другом подобном императивном языке. Мы не ожидаем опыта работы с более современными или богатыми возможностями языками, такими как Swift, Kotlin, C# или TypeScript.

Основы проектирования API

  • Золотое правило: отдавайте приоритет ясности и читаемости в месте вызова. Люди будут тратить гораздо больше времени на чтение мест вызова, чем на объявления вызываемых функций.
  • Сделайте ваш API предсказуемым
    • Следуйте соглашениям об именовании (регистр и привычная лексика стандартной библиотеки: например, методы должны называться «push», а не «push_back», «is_empty», а не «empty» и т. д.)
    • Знайте типы и трейты-словари стандартной библиотеки и используйте их в своих API. Если что-то похоже на базовый тип или алгоритм, сначала проверьте стандартную библиотеку.
    • Используйте устоявшиеся паттерны проектирования API, которые мы обсудим позже на этом курсе (например, newtype, пары «владеющий тип / тип-представление», обработка ошибок)
  • Пишите содержательные и полезные doc-комментарии (например, не просто повторяйте имя метода с пробелами вместо подчёркиваний, не повторяйте одну и ту же информацию только ради заполнения всех тегов Markdown, приводите примеры использования)

Использование системы типов

  • Краткое повторение перечислений, структур и псевдонимов типов
  • Паттерн newtype и инкапсуляция: разбирайте, а не проверяйте (parse, don’t validate)
  • Трейты-расширения: не используйте паттерн newtype, если хотите добавить дополнительное поведение
  • RAII, охранники области видимости и «бомбы» drop: использование Drop для очистки ресурсов, запуска действий или обеспечения инвариантов
  • Типы-«токены»: заставляют пользователей доказать, что они выполнили определённое действие
  • Паттерн typestate: обеспечивает корректные переходы состояний во время компиляции
  • Использование анализатора заимствований для обеспечения инвариантов, не имеющих отношения к владению памятью
    • OwnedFd/BorrowedFd в стандартной библиотеке
    • Branded-типы

Не боритесь с анализатором заимствований

  • Типы «владеющие» и типы-«представления»: &str и String, Path и PathBuf и т. д.
  • Не скрывайте требования к владению: избегайте скрытого .clone(), научитесь любить Cow
  • Разделяйте типы по границам владения
  • Структурируйте иерархию владения как дерево
  • Стратегии управления циклическими зависимостями: подсчёт ссылок, использование индексов вместо ссылок
  • Внутренняя изменяемость (Cell, RefCell)
  • Работа с параметрами времён жизни в пользовательских типах данных

Полиморфизм в Rust

  • Краткое повторение трейтов и обобщённых функций
  • В Rust нет наследования: каковы последствия?
    • Использование перечислений для полиморфизма
    • Использование трейтов для полиморфизма
    • Использование композиции
    • Как выбрать наиболее подходящий паттерн?
  • Работа с обобщениями
    • Обобщённый параметр типа в функции или объект трейта в качестве аргумента?
    • Ограничения трейтов не обязаны ссылаться на обобщённый параметр
    • Параметры типа в трейтах: должен ли это быть обобщённый параметр или ассоциированный тип?
  • Макросы: ценный инструмент, чтобы избежать повторений (DRY), когда трейтов недостаточно (или они слишком сложны)

Обработка ошибок

  • Для чего нужны ошибки? Восстановление или сообщение о проблеме.
  • Result и Option
  • Проектирование хороших ошибок:
    • Определите область действия ошибки.
    • Добавляйте дополнительный контекст по мере подъёма ошибки вверх, пересекая границы областей видимости.
    • Используйте трейт Error, чтобы отслеживать всю цепочку ошибок.
    • Используйте thiserror, чтобы сократить шаблонный код при определении типов ошибок.
    • anyhow
  • Отличайте фатальные ошибки от восстанавливаемых, используя Result<Result<T, RecoverableError>, FatalError>.