Добро пожаловать в идиоматичный Rust
Основы Rust познакомили с синтаксисом Rust и основными концепциями. Теперь мы хотим пойти дальше: как эффективно использовать Rust в ваших проектах? Как выглядит идиоматичный Rust?
Этот курс имеет своё мнение: мы будем подталкивать вас к одним паттернам и отговаривать от других. Тем не менее мы понимаем, что у некоторых проектов могут быть другие потребности. Мы всегда приводим необходимую информацию, чтобы помочь вам принимать обоснованные решения в контексте и рамках ваших проектов.
⚠️ Этот курс находится в активной разработке.
Материалы могут часто меняться, и могут быть ошибки, которые ещё не заметили. Тем не менее мы призываем вас просмотреть их и дать ранний отзыв!
Расписание
Включая 10-минутные перерывы, это занятие займёт около 14 часов 10 минут. Оно включает:
| Сегмент | Длительность |
|---|---|
| Основы проектирования API | 3 часа 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>.