Я наблюдаю за тем, как люди снова и снова совершают одни и те же ошибки при изучении Rust. Ниже представлены мои мысли (в порядке важности) о том, как можно упростить себе процесс обучения. Моя цель — помочь вам сэкономить время и избежать разочарования.

Расслабьтесь

Перестаньте сопротивляться. Это самый важный урок.

Примите то, что для изучения Rust требуется освоение совершенно иной и непривычной вам ментальной модели. В языке есть куча новых концепций, например сроки жизни, владение и система трейтов. В некоторых случаях для вас будут новыми дженерики, сопоставление с образцом или макросы.

Темп обучения не особо зависит от вашего ума и предыдущего опыта программирования. Главнее всего ваше отношение к языку.

Я видел разработчиков-джунов, прекрасно справлявшихся с Rust без предварительного обучения, и сениоров, которые боролись с ним неделями/месяцами или полностью капитулировали. Забудьте о своей гордыне.

Считайте borrow checker своим соавтором, а не противником, благодаря этому вы взглянете на ваши отношения с ним иначе. Позвольте компилятору обучать вас: например, это замечательно работает в случае со сроками жизни, потому что компилятор сообщит вам, когда срок жизни неоднозначен. Затем просто добавьте его, но в то же время поразмыслите над тем, почему компилятор не смог определить его самостоятельно.

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

Если вы попробуете скомпилировать этот код, компилятор попросит добавить параметр срока жизни. Он даст следующую полезную рекомендацию:

1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  |           ++++     ++          ++          ++

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

Чаще всего, когда вам приходится бороться с компилятором — это указывает на изъян в структуре кода. Аналогично, если ваш код стал слишком многословным или некрасивым, то, вероятно, существует более качественное решение. Объявите о своём поражении и учитесь работать в стиле Rust.

Если в прошлом вы работали с динамическими языками наподобие Python, то в общем случае Rust покажется вам более многословным. Однако в основном это связано с сигнатурами типов. Кто-то может отказаться от Rust из-за того, что он «неэлегантный» или «некрасивый», но его многословность на самом деле идёт на пользу: она крайне полезна при создании крупномасштабных приложений:

  • Во-первых, читать код вы будете гораздо чаще, чем писать его, то есть сигнатуры типов дадут вам больше локального контекста, о котором можно рассуждать.

  • Во-вторых, это невероятно полезно при рефакторинге, потому что компилятор может проверить, не поломали ли вы что-то при перемещении блоков кода. Если окажется, что ваш код очень некрасив, то вернитесь на шаг назад и задайтесь вопросом, нет ли более простого решения. Не отказывайтесь от языка сразу.

С самого начала освоения включите все проверки стиля clippy, даже самые педантичные. Запустите линтер и тщательно выполняйте все рекомендации. Не пропускайте этот этап сразу после того, как программа начала компилироваться.

Сопротивление бесполезно. Чем дольше вы отказываетесь учиться, тем дольше будете страдать; но в тот момент, когда вы расслабитесь, вы и начнёте учиться. Забудьте то, что вы знали о программировании (как вам казалось) и начните по-настоящему прислушиваться к тому, что вам пытаются сказать компилятор, стандартная библиотека и clippy.

Маленькие шаги

Сам я точно пытался бегать ещё до того, как научился ходить. Лишь одно это стоило мне кучи драгоценного времени.

Не стоит в самом начале требовать от себя слишком многого. Вот некоторые рекомендации:

  • Щедро пользуйтесь String, clone() и unwrap; вы всегда сможете в дальнейшем выполнить рефакторинг, а это самая лучшая часть Rust! Я написал статью о том, как можно экономить время на этом этапе.

  • Поначалу используйте простые конструкции if или match , а уже потом приступайте к изучению более идиоматических комбинаторов наподобие .and_then

  • В первую неделю избегайте асинхронного Rust. Дополнительные правила — лишняя нагрузка на людей, изучающих базовую модель владения.

Не внедряйте в код слишком много концепций одновременно! При изучении новой концепции имейте под рукой открытый редактор и запишите несколько примеров. Мне помогало писать код в песочнице Rust и пытаться заставить его скомпилироваться. Пишите максимально маленькие блоки кода (например, один main.rs для одной концепции), а не используйте один большой репозиторий-«туториал». Возьмите за привычку выбрасывать бóльшую часть кода.

Я продолжаю это делать и тестирую идеи в песочнице или когда мы проводим мозговой штурм с заказчиками.

Например, вот один из моих любимых блоков кода, объясняющий концепцию владения (ownership):

fn my_func(v: String) {
    // делаем что-то с v
}

fn main() {
    let s = String::from("hello");
    my_func(s);
    my_func(s); // ошибка, но почему?
}

Можете устранить её? А объяснить? Задайтесь вопросом, что изменилось бы, если бы v имела тип i32.

Если код на Rust пугает вас, разбивайте его на части. Пишите свои собственные упрощённые версии, а затем постепенно повышайте сложность. На Rust проще писать, чем читать. Написав кучу кода на Rust, вы научитесь и лучше читать его.

Будьте точны

То, как вы делаете одно, вы делаете и всё остальное. – древняя поговорка о Rust

Можно быть расхлябанными в других языках, но не в Rust. Это значит, что вам нужно быть точным с кодом, или он просто не скомпилируется. Следует ожидать, что такой подход сэкономит вам в будущем время на отладку.

Я заметил, что люди, быстрее всех изучающие Rust, очень внимательны к деталям. Если вы стремитесь просто выполнить задачу и двигаться дальше, то вам будет сложнее, чем тому, кто хочет сразу сделать всё правильно. Вам будет гораздо проще, если вы будете перечитывать свой код и исправлять дурацкие опечатки перед нажатием на «compile». Кроме того, развейте в себе привычку автоматически добавлять прямо в процессе кодинга & и mut там, где это необходимо.

Хороший пример человека, обдумывающего такие подробности при кодинге — это Tsoding. Например, посмотрите его стрим, на котором он с нуля пишет поисковый движок на Rust. Я считаю, что вы сможете освоить этот навык, если приложите максимум усилий и потратите достаточно времени.

Не жульничайте

Работая с современным инструментарием, очень легко переложить основную часть работы на компилятор. Поначалу будет казаться, что вы быстро развиваетесь, но на самом деле это усиливает ваши плохие привычки в процессе работы. Если вы не можете объяснить другому человеку, что вы написали, или не знаете о компромиссах/допущениях в части вашего кода, то вы зашли слишком далеко.

Часто такой подход произрастает из страха того, что вы двигаетесь недостаточно быстро. Но вам не нужно доказывать кому-то, что вы достаточно умны, чтобы очень быстро освоить Rust.

Пройдите путь

Чтобы правильно изучать Rust, вам нужно писать много кода вручную. Не будьте тем, кто читает на Reddit чужие истории успеха. Будьте настойчивы! Тратьте часы, потому что «серебряной пули» здесь не существует. Как только начнёт получаться, подумайте над выкладыванием своего кода в опенсорс, даже если вы знаете, что он неидеален.

Не двигайтесь на автопилоте

Работа с LLM подобна управлению машиной на автопилоте. Поначалу это удобно, но вы не будете ощущать контроля, и постепенно вами овладеет чувство беспокойства. Отключите автопилот, пока учитесь.

Для быстрого движения к успеху следует сначала писать код в Rust Playground. Не пользуйтесь LLM и автодополнением кода. Вводите всё сами! Если не можете, это значит, что вы не полностью освоили концепцию. И это нормально! Изучите стандартную библиотеку и читайте документацию. Уделите этому нужное количество времени, а потом возвращайтесь к кодингу.

Здесь медленно — это стабильно, а стабильно — это быстро.

Нарабатывайте мышечную память

Мышечную память в программировании сильно недооценивают. Вам будут говорить, что её можно заменить автодополнением, но я считаю, что она обязательна для достижения состояния потока: если вы постоянно сталкиваетесь с синтаксическими ошибками или просто ждёте следующего автодополнения, чтобы двигаться дальше, то это не пойдёт на пользу разработке.

В процессе написания кода вручную вы будете совершать больше ошибок. Смиритесь с ними! Эти ошибки помогут вам понять сообщения компилятора. У вас возникнет понимание того, как выглядят сообщения при разных сценариях ошибок. Не следует рассматривать эти ошибки мельком. Со временем у вас выработается интуиция о том, что же такое стиль Rust.

Прогнозируйте результат

Я люблю делать упражнения с прогнозированием, в которых перед запуском кода я предсказываю, скомпилируется ли он. Так нарабатывается интуиция. Попытайтесь избавлять каждую программу от синтаксических ошибок перед запуском. Не будьте небрежны. Разумеется, получаться будет не всегда, но со временем вы станете справляться гораздо лучше.

Пытайтесь решать задачи самостоятельно, и только потом искать готовое решение

Читайте много чужого кода. Я рекомендую, например, ripgrep, это один из лучших примеров кода на Rust.

Подберите хорошее соотношение между чтением и написанием кода

Не бойтесь сложной работы. Каких сфер Rust вы стараетесь избегать? От чего вы бежите? Сосредоточьтесь на этом. Прорабатывайте свои «слепые пятна». Отслеживайте часто применяемые вами «спасательные круги» (unsafe, clone и так далее), чтобы выявить свои слабые стороны. Например, если вы боитесь макросов proc, то напишите целую кучу их.

Ломайте свой код

Закончив с упражнением, поломайте его! Прочитайте, что говорит компилятор. Попробуйте объяснить, что произошло.

Не используйте при обучении чужие крейты

Плохое личное видение лучше, чем идеальный внешний крейт (по крайней мере, в процессе обучения). Напишите самостоятельно код небольшой библиотеки в качестве упражнения. В качестве исключений можно упомянуть serde и anyhow, которые сэкономят вам много времени при работе с входящими JSON и настройке обработки ошибок; это время можно будет потратить на другие задачи.

Нарабатывайте правильную интуицию

В концепциях наподобие сроков жизни сложно разобраться. Иногда бывает полезно составить диаграмму перемещения данных по системе. Выработайте привычку объяснять себе и другим концепции при помощи рисунков. Я не уверен, но мне кажется, что это лучше всего работает у «визуалов»/творческих людей (в отличие от аналитичных людей).

Лично я для рисования использую excalidraw. У него «комиксовый» стиль, что позволяет немного расслабиться. Диаграммы не кажутся особо точными и служат в качестве грубого наброска. Многие хорошие инженеры (а также отличные математики и физики) способны визуализировать концепции при помощи набросков.

В Rust наброски могут помочь в визуализации сроков жизни и владения данными, а также при составлении диаграмм архитектуры.

Надстраивайте свои знания поверх того, что уже понимаете

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

Я имел в виду, что Rust сильнее всего отличается от других языков в знакомых вам областях, например, в обработке потока управления и передаче значений. К примеру, изменяемость задаётся в Rust очень явным образом и вызов функции обычно «перемещает» её аргументы. Здесь вам нужно принять, что Rust просто другой, и учиться с первооснов.

Однако вы вполне можете сопоставлять концепции Rust с другими известными вам языками. Например, утверждение «трейт немного похож на интерфейс» ошибочно, но с этого вполне можно приступить к пониманию концепции.

Вот ещё несколько примеров:

  • «struct похожа на класс (минус наследование)»

  • «замыкание похоже на лямбда-функцию (но может запоминать переменные)»

  • «модуль похож на пространство имён (но более мощный)»

  • «заимствование похоже на указатель (но с единственным владельцем)».

А если у вас есть опыт функционального программирования, то примеры могут быть такими:

  • «Option похожа на монаду Maybe»

  • «трейты похожи на класс типов»

  • «перечисления — это алгебраические типы данных»

Смысл в том, что сопоставление концепций помогает быстрее заполнить пробелы в понимании.

Сопоставляйте то, что вы знаете в других языках (например, Python, TypeScript), с концепциями Rust. Если вы осознаёте, что существуют небольшие различия, это будет полезно.

Я нечасто встречаю упоминания этого, но мне кажется, Rosetta Code — отличный ресурс для этого. По сути, вы просматриваете список задач, выбираете понравившуюся и начинаете сравнивать решение на Rust с решением на самом знакомом вам языке.

Также стоит портировать код с известного вам языка на Rust. Благодаря этому вам не придётся каждый раз осваивать новую предметную область параллельно с изучением Rust. Вы можете основываться на уже имеющихся знаниях и опыте.

  • Переводите распространённые идиомы знакомого вам языка на Rust. Например, как преобразовать генератор списка с Python на Rust? Сначала попробуйте сами, потом поищите ресурсы, которые объяснят эту концепцию в Rust. Например, я сам написал статью по этой теме.

  • Я знаю людей, которые портируют несколько стандартных упражнений на каждый новый изучаемый язык. Например, это может быть трассировщик лучей, алгоритм сортировки или небольшое веб-приложение.

Также стоит найти людей, имеющих схожий с вашим опыт. Читайте их блоги, в которых они говорят о своём процессе изучения Rust. Составляйте заметки и о своём прогрессе.

Не гадайте

Я заметил, что люди, которые склонны угадывать решения, испытывают больше всего трудностей в изучении Rust.

В Rust детали — это главное. Не обходите детали, потому что они всегда раскрывают какую-нибудь мудрость о решаемой задаче. Даже если вас не интересуют детали, позже они обязательно на вас отыграются.

Например, зачем нужно вызывать to_string() для того, что уже и так строка?

my_func("hello".to_string())

Эти непонятности — возможность для роста. Кажется, что задавать такие вопросы — это тратить время впустую и замедлять решение задачи, но в долговременной перспективе они оправдают себя.

Внима-а-ательно читайте выводимые компилятором сообщения об ошибках. Все думают, что так и делают, но постоянно оказывается так, что люди заходят в тупик, когда решение приведено прямо в терминале. Также существуют hint; не игнорируйте их. Лишь это одно сэкономит вам очень много времени. Потом скажете мне «спасибо».

Вы можете сказать, что это справедливо для любого языка, и будете правы. Но в Rust сообщения об ошибках действительно стоят изучения. Некоторые из них похожи на небольшие медитации: это возможность поразмыслить над задачей на более глубоком уровне.

Если вы получаете какие-то ошибки borrow checker, то не гадайте, что происходит. Вместо этого вручную пройдитесь по потоку данных (разберитесь, кто, когда и чем владеет). Попытайтесь всё продумать самостоятельно и запускайте компиляцию, только когда поймёте проблему.

Придерживайтесь Type-Driven Development

Основа хорошего кода на Rust — система типов.

В системе типов есть всё. Всё, что вам нужно, прячется на ровном месте. Но зачастую люди слишком забывают о документации и смотрят только на примеры.

Немногие читают документацию к функциям. Вы можете понажимать по стандартной библиотеке до исходного кода, чтобы прочитать, что в ней используется. В этом нет никакой магии (и в этом заключается вся магия).

В Rust это можно делать гораздо лучше, чем в большинстве других языков программирования, потому что, например, Python написан на C, поэтому для углублённого понимания вам приходится пересекать границы языка. Аналогично, стандартная библиотека C++ — это не единая стандартизованная реализация, а множество различных реализаций, поддерживаемых разными организациями. Это сильно усложняет процесс анализа происходящего. В Rust исходный код доступен прямо внутри документации. Пользуйтесь этим!

О многом вам скажут сигнатуры функций! Чем раньше вы начнёте использовать эту дополнительную информацию, тем быстрее освоитесь в Rust. Если у вас есть время, читайте интересные части документации стандартной библиотеки. Даже спустя годы изучения я всегда нахожу в них что-то новое.

Попробуйте моделировать свои проекты, начиная с типов. Именно так вы начнёте получать гораздо больше удовольствия от языка. Это будет похоже на беседу с компилятором о задаче, которую вы хотите решить.

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

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

Изучайте Rust через type-driven development и позвольте ошибкам компилятора руководить структурой кода.

Потратьте время на поиск хороших обучающих ресурсов

Прежде чем начинать, поищите ресурсы, соответствующие вашему личному стилю обучения. Откровенно говоря, качественных источников пока мало. С другой стороны, вам не придётся слишком долго изучать список ресурсов перед тем, как остановиться на конкретной платформе/книге/курсе. Подбирайте ресурс под собственный тип обучения. В долговременной перспективе выбор подходящего ресурса сэкономит вам время, потому что вы будете учиться быстрее.

Лично мне не нравится делать учебные упражнения, придуманные кем-то ещё. Именно поэтому я не особо люблю Rustlings; упражнения не увлекательны и они слишком теоретические. Мне нужны более практичные задания. Я выяснил, что мне больше подходят Project Euler и Advent of Code. Этот вопрос всплывает достаточно часто, поэтому я написал пост о моих любимых обучающих ресурсах по Rust.

Не нужно просто смотреть YouTube

Я люблю смотреть YouTube, но только в качестве отдыха. На мой взгляд, просмотр ThePrimeagen — это лишь развлечение. Он потрясающий программист, но учиться программировать, наблюдая за тем, кто пишет код — это как пытаться стать спортсменом, смотря Олимпиаду. Аналогично, думаю, всем мы согласны с тем, что Йон Йенгсет — выдающийся программист и преподаватель, но если вы только начинаете учиться, то его видео могут утомлять. (Хоть мне и нравится его контент!)

То же самое относится и к докладам с конференций и подкастам: они отлично подходят для получения контекста и для обучения «мягким» навыкам, но не для изучения Rust.

Вместо всего этого купите хорошую книгу. Книги ещё не устарели и их можно читать офлайн, добавлять примечания, самостоятельно вводить код и получать «пространственный обзор» глубины контента перелистыванием страниц.

Если же вы серьёзно настроены работать с Rust профессионально, купите курс или попросите начальство потратить деньги на преподавателя. Разумеется, я здесь крайне предвзят, потому что управляю консалтинговой фирмой по Rust, но я действительно уверен в том, что это сэкономит вам и вашей компании бесчисленное количество часов, а в долговременной перспективе приведёт к успеху. Задумайтесь: вы будете работать с этой кодовой базой ещё долгие годы, поэтому лучше сделать этот опыт приятным. Хороший преподаватель не будет просто читать с вами книгу по Rust, а понаблюдает за тем, как вы сами программируете на Rust, и даст вам персональную обратную связь о ваших слабых сторонах.

Найдите себе напарника

Станьте «тенью» более опытных членов команды или друзей.

Не бойтесь просить код-ревью в Mastodon или на форуме Rust, а потом окажите ответную услугу и сами выполняйте код-ревью. Пользуйтесь возможностью парного программирования.

Объясняйте код на Rust тем разработчикам, которые на нём не пишут

Это потрясающий способ проверить, действительно ли вы поняли концепцию. Не бойтесь говорить «я не знаю». Вместе ищите ответы, обратившись напрямую к документации. Это гораздо честнее и полезнее.

Помогайте с открытым кодом, который был заброшен. Если вы приложите достаточные усилия к починке неподдерживаемой кодовой базы, то поможете другим, параллельно обучаясь работать с чужим кодом на Rust.

Читайте код вслух и объясняйте его. В этом нет ничего постыдного! Это помогает «сериализовать» ваши мысли и не упустить важные детали.

Ведите заметки. Составьте собственный небольшой «глоссарий Rust», где будет сопоставляться терминология Rust и концепции в вашей предметной области бизнеса. Он необязательно должен быть полным, достаточно, чтобы отвечал вашим потребностям.

Записывайте то, что оказалось для вас сложным, и то, чему вы научились. Если найдёте отличный обучающий ресурс, расскажите о нём другим!

Верьте в преимущества в дальней перспективе

Если вы изучаете Rust для того, чтобы указать его в своём резюме, то прекращайте. Изучите что-нибудь другое.

Я считаю, что для получения удовольствия от Rust вам по-настоящему должно нравиться программирование (а не только её идея).

Если вы хотите достичь успеха с Rust, то приготовьтесь к долгому пути. Ваши ожидания должны быть реалистичными: вы не станете «гроссмейстером Rust» за неделю, но за месяц сосредоточенной работы сможете достичь многого. «Серебряной пули» нет, но если вы избежите самых распространённых способов выстрелить себе в ногу, то освоите язык гораздо быстрее. Rust не изучается за день. Вы не будете ощущать себя «продуктивным», как после первой недели освоения Go или Python, но потерпите, и усилия себя оправдают. Удачи, и получайте удовольствие!

Комментарии (9)


  1. pnmv
    15.05.2025 13:21

    в качестве черновика перевода, сгодится. если кратко: необходима вычитка.


  1. kovserg
    15.05.2025 13:21

    Язык который не позволяет сделать простые вещи просто - тупиковая ветвь. Но это видимо не очевидно. Раст яркий пример когда взяв всего один приём пытаются им решить все вопросы, но при этом создают проблемы с которыми придётся иметь дело позже. И если "в системе типов есть всё" есть много желающих запихать туда еще больше. В результате распухание сложности гарантировано. При этом вообще-то никак не решена проблема разрастания зависимостей. Зато надо следить за большим количеством сущностей.

    https://youtu.be/bKyxOaP-mDg?t=3120


  1. plyaj
    15.05.2025 13:21

    Ох, эти американизированные статьи и книги по деланью чего-то очень забавные. Можно как в фильмах Марвел поменять героев, оставив сценарий, вот и новый фильм на миллиард баксов сборов готов. По такому же принципу работает и чтиво. Можно поменять тему, но основу книги/статьи оставить - вот и новый контент.

    P.S.
    За перевод спасибо :)


  1. kirrp
    15.05.2025 13:21

    Неужели rust стоит того, программируя на нем, проходя через все эти препядствия? Переосмысливать все программирование и претерпевать эти страдания с новыми конценпциями? Мне кажется, что не cтоит.


    1. andreymal
      15.05.2025 13:21

      Тысячи уязвимостей в сишных программах наглядно демонстрируют что стоит


      1. Dhwtj
        15.05.2025 13:21

        Не только замена C/C++ но и Java/C#/Go

        Rust имеет очень неплохие фичи из функциональщины, что полезно в корпоративных бизнес системах, системах со сложными бизнес процессами.

        Порог входа для них высокий, ага

        IDE + LLM в помощь!


  1. yttrium
    15.05.2025 13:21

    Если нужно простое решение - решайте простыми инструментами, они некуда не деваются, их никто не заменяет. Например, ядро linux - это не простое решение, поэтому это не решается простыми инструментами. Иными словами просто появляется инструмент который занимает свою нишу. Он не идеален, но развивается. Возможно появится другой инструмент который сможет гораздо круче решать разные классы задач, и он будет учитывать этот опыт, поэтому пройти эту эволюцию человечество должно.


  1. Dhwtj
    15.05.2025 13:21


  1. Siemargl
    15.05.2025 13:21

    Никак не пойму, зачем сделано так неудобно.

    1 Пример 1й. fn longest(.

    1.1 Почему компилятор, отлично умеющий высчитывать лайфтаймы, не может здесь сделать автовывод лайфайма?

    1.2 функция чистая, зачем вообще в ней вычисляется владение?