Русский
Русский
English
Статистика
Реклама

Перевод Юмористичный обзор Rust с перспективы JavaScript


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

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

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

Хорошие новости


Современный Rust оказывается весьма схож с JavaScript. Переменные объявляются через let, функции выглядят очень похоже, типы уже не чужды, так как мы привыкли к TypeScript, присутствуют async/await, да и в общем формируется весьма знакомое ощущение.

Плохие новости


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

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

Управлению памятью быть!


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

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

Когда речь заходит об управлении памятью, то Rust как бы говорит: Ничего не знаю реальные шеф-повара сами за собой убирают. И на то есть хорошая причина, потому что сборщик мусора несет в себе собственный набор неочевидных проблем, которые могут навредить в самый неожиданный момент. Хотя в то же время, обогащенный опытом других языков, Rust признает, что заставлять программиста управлять памятью столь же разумно, сколь поручить Дугласу Адамсу написать Звездолет Титаник.

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



Как розу ты ни назови, а запах ее столь же сладок


верно сказал Шекспир. Хотя, как быть с не столь ароматными запашками? Сохраняется ли верность его слов в обратном случае? Учитывая многовековую традицию использования людьми эвфемизмов, можно с уверенностью заключить, что нет.


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

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

На землях Вестероса (смею я сказать ВестеRust?) есть крохотные, небольшие, а также крупные феоды. Загвоздка в том, что все они оккупированы Ланнистерами. Внутренне феоды занимаются своими собственными делами, а когда им требуются товары извне, то они берут на себя долг, чтобы эти товары получить. В последствии долг необходимо возвращать Богам Вестероса. Rust подобен королеве драконов этого мира он узрит свысока все нюансы и проследит, чтобы все долги перед Богами были уплачены.

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

Может ли возникнуть кризис?


Посмотрим, как это работает.



Здесь у нас две области: внешняя main и внутренняя, будем звать ее inner scope, для демонстрации. В этом случае владение работает так:

  1. main владеет a и b
  2. a хочет поработать в inner scope, поэтому main передает a во владение inner scope
  3. inner scope делает свои дела с a и завершается
  4. Скрытый код Rust отбрасывает a
  5. main делает свои дела с b и тоже завершается
  6. Rust отбрасывает b

Обратите внимание, что долг, обусловленный владением, возвращается системе, а не области, из которой возник. Владение a не возвращается в область main. Так, подождите звучит очень опасно.

Что, если у нас будет такой код?



Здесь область main хочет снова использовать a, но мы сказали, что Rust уже ее отбросил по завершении inner scope.

Не даст ли программа сбой и не сгорит ли, когда достигнет этой точки выполнения?



Да, так и будет. Но, как спартанцы ответили отцу Александра, королю Филиппу II Македонскому: если она этой точки достигнет.

Абсолютный бюрократ


Компилятор Rust является гордым послушником традиции Легизма, настолько верным, что Хан Фей-цзы с восторгом бы объявил вне закона все остальные языки. Ничто не происходит в землях Rust, пока компилятор не скрепит это действие печатью Утверждаю. Он будет тщательно проверять каждую мелочь, оценивая, насколько безопасен запуск программы, и только при удовлетворении всех требований выдаст-таки исполняемый файл.



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

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

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

Rust RPG


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

Помните пример с dbg!()? Это макрос, представляющий грубый эквивалент console.log из JS. Давайте создадим собственную типизированную переменную и выведем ее в консоль.



Мы создали struct, которая, по сути, является типом. Затем мы создали объект этого типа. В завершении мы запросили вывод созданного объекта.



Ну дела. Наш игрок до такой степени нуб, что даже не может предоставить отладочную информацию. Правда! Просто удивительно

Ключевой момент здесь в том, что ваши рукотворные переменные все начинают в пешках без всякого снаряжения. А вот где вступает в игру и само снаряжение (на языке Rust называемое типажи (Trait)).

Нажмем F.



На этот раз работает. Единственное отличие в появившейся сверху строке. Здесь мы снаряжаем Noob типажом Debug. Теперь наш игрок готов к выходу в консоль какое достижение!

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

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

Типажи являются глубинным принципом работы фабрики Rust. Вернемся еще раз к примеру с владением. Если внимательно прочесть сообщение об ошибке, то мы заметим в нем компилятор объясняет, что владение переменной пришлось переместить, потому что String не реализует типаж Copy. В противном случае компилятор не стал бы ее перемещать, а сделал копию.

Типаж Copy означает, что вы берете раздел памяти и memcpy его в другое место, работая непосредственно с байтами. Хорошо, значит String не имеет типажа Copy, нужно ли нам просто сообщить компилятору, чтобы он его присвоил? К сожалению, нет. В целях безопасного использования Copy является слишком низкоуровневой для применения к String.

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

В качестве примера немного подправим код:



Здесь компилятор видит, что нам нужно использовать a внутри inner scope, но теперь он также видит, что мы научились все делать правильно, задействовав вместо фактической a ее клона. Итак, получается следующее:

  1. a принадлежит main
  2. Создается a.clone и одалживается в inner scope
  3. inner scope делает свои дела и завершается
  4. Rust отбрасывает a.clone
  5. main без проблем использует a, потому что a всегда оставалась в ее владении

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

Прежде чем завершать пост, считаю необходимым вкратце проговорить еще кое-что. Мы рассмотрели владение и то, как оно реализуется в области, но правда в том, что это было всего лишь упрощение. Для отслеживания владения Rust задействует принцип времени жизни (Lifetimes). Просто, получается, что чаще всего времена жизни и области совпадают. Хотя иногда компилятору все же требуется помощь. Следовательно, мы можем работать напрямую с временами жизни, а в некоторых случаях даже обязаны.

Конец?


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

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


Источник: habr.com
К списку статей
Опубликовано: 16.06.2021 20:20:54
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании ruvds.com

Ненормальное программирование

Javascript

Rust

Ruvds_перевод

Юмор

Перспективы

Категории

Последние комментарии

© 2006-2021, personeltest.ru