- PVSM.RU - https://www.pvsm.ru -
Всем привет! Сегодня хочу поделиться опытом изучения языка и быстрой реализации высоконагруженного сетевого проекта, использующего так популярные и востребованные сейчас неблокирующие асинхронные сетевые соединения, на новом, красивом, элегантном и очень эффективном языке Rust.
Особый упор в посте сделаю на быстрое и ясное объяснение возможностей языка и платформы специалистам, имеющим большой опыт в веб-разработке, ибо сам таким и являюсь. Существует заблуждение, что кривая вхождения в Rust — очень-очень крутая. Но я покажу, что это далеко не так. Наливаем кофе и погнали!
Чтобы материал хорошо залег в голову и сердце, неплохо кратко вспомнить, что люди хотели сделать в программировании за последние 50 лет и что в итоге у них получилось. Без обид, только личное субъективное мнение и холивар, подкрепленный 20-летним опытом разработки.
Понятно, что можно писать программу сразу в виде цифр на машинных кодах и многие этим занимались на ZX Spectrum, БК0010-01 и на PC — код получается очень быстрым :-) Но мы люди, в голову много информации не помещается, мы отвлекаемся и поэтому даже изобретение ассемблера не особо помогло — код на таком низком уровне пишется очень редко и очень метко и, скорее всего, если вы не занимаетесь разработкой драйверов, микроконтроллеров или хитрых встраиваемых систем, это в жизни не пригодится.

В начале 70-х в Bell Labs придумали язык C, который прижился благодаря лаконичному синтаксису и очень «дешевым» абстракциям, практически став «переносимым ассемблером». Понятно, что если принять постриг, 10 лет писать на C ночами, не есть мясо, молиться и не отвлекаться на соцсети и формы прекрасного пола, то можно писать очень даже полезные и быстрые программы, о чем красноречиво свидетельствуют GNU [1], прекрасные производительные игры, не всеми любимая, но безальтернативная по качеству Windows и еще можно привести много примеров.
Но обратная сторона медали постоянно дает о себе знать — регулярно открываемые дырки в безопасности (создана целая индустрия по «дыркам в софте»), обусловленные дырками в концепции самого языка С — компилятор подобен безответственному быку, с неимоверной мощью, интенсивным оргазмом и короткой памятью. Любая неосторожность — и можно не просто уронить программу (разыменование нулевого указателя, двойное освобождение указателя, выход за пределы массива), а безвозвратно испортить данные и долго этого не замечать, пока не начнут звонить клиенты и когда уже поздно («неопределенное поведение», отличающееся от компилятора к компилятору).
Бьёрн Страуструп только еще больше запутал ситуацию в начале восьмидесятых, добавив возможности ООП к C. Несмотря на большую популярность, С++, в целом, видится как серия экспериментов над программированием, как таковым, с разной успешностью исходов, в т.ч. летальных. Иногда даже кажется, что смысла в C++ не было с самого начала, либо он был постепенно утерян, родив в результате нагромождение объективно переусложненных и противоречащих друг другу концепций, которых становится все больше и больше с каждым новым стандартом. Несмотря на отличную цель «zero-cost абстракции», позволяющие получать быстрый код, для создания надежного решения, как и на С, требуется выполнение следующих условий:
Понятно, что соблюдение указанных требований, особенно в контексте возрастающей потребности бизнеса на «работающий без внезапных сюрпризов код», очень дорого. Код в подобных проектах пишется долго, тестировать его нужно продолжительное время и тщательно, но, иногда, без C/C++, до изобретения Rust, действительно сложно БЫЛО обойтись.
Еще раз резюме по С/C++ — мы имеем мощный, но «безответственный» компилятор с «текущими абстракциями», очень мало помогающий разработчику. В результате все проблемы перекладываются на плечи программиста. Если хоть один программист в команде не опытный, не очень осторожный и не знает всех тонкостей работы компилятора (на самом деле никто не знает всех тонкостей и их находят пользователи потом) — жди беды. Но зато программа работает быстро и, вероятно, правильно :-) Это, разумеется, породило целый рынок «костылей» — статических анализаторов, платить за которые должен, как оказалось, Заказчик. Возникает вопрос — а разве нельзя было что ли написать более строгий и безопасный компилятор, помогающий разработчику и рождающий программы без сюрпризов и низкоуровневых дырок в безопасности?
Ситуация с откровенно слабым контролем «неопределенного поведения» и очень высокими требованиями к разработчикам в C/C++ породило желание сделать безопасную среду разработки, в т.ч. для интернета, доступную большинству желающих. Так в конце 90-х появилась Java.
В принципе, теперь любой желающий с разным уровнем подготовки мог писать все, что угодно и как угодно и ОНО РАБОТАЛО и что в программу не засовывай — низкоуровневых «дырок» в безопасности и спонтанных крешей уже не было (почти, но они уже были вызваны багами в виртуальной машине и исправлялись централизованно). Оставались только логические «дырки» или скрытый медленный код (рожденный незнанием алгоритмов, понятия алгоритмической стоимости и тормозящий при увеличении объема данных), который был уже не так страшен и позволяет делать программы быстро, а при необходимости — переписывать маленькие куски квалифицированной командой на C/C++.
Интересные и ценные вещи, которые принесла в мир Java, следующие:
Разумеется, появление такой дружелюбной платформы позволило писать много полезных и бесполезных программ, чем сразу воспользовался бизнес. А поддержка обратной совместимости в Java в 15 и более лет обусловила такую популярность технологии в мире энтерпрайза.
Да, у меня тоже возникают аналогии с безалкогольным пивом и резиновыми женщинами.
Однако, далеко не сразу, в Java вылезли следующие проблемы:
После прочитанного должно быть понятно, что все на Java писать нельзя, это будет писаться довольно медленно, потом будет под нагрузкой регулярно тормозить и зависать на секунды, «жрать» иногда много оперативной памяти (обычно съедается как минимум половина ОЗУ на сервере), производительные игры тоже не попишешь, но какие-то куски бизнес-логики, не особо требовательные к производительности и ОЗУ, особенно многопоточные — вполне можно, полезно и поэтому мы видим такую популярность технологии в мире энтерпрайза. И мы сами регулярно и активно используем Java для сервисов компании.
«А когда же будет про Rust?» — погодите, нужно еще чуть-чуть подготовиться скушать эту сладкую хурму. Если не рассказать об особенностях других технологий, вы не поймете, почему появился Rust и почему от такой популярный и востребованный [3].
Итак, пытаясь сделать Java лучше и прогрессивнее, Microsoft, в лице автора TurboPascal/Delphi, в начале нулевых придумал C# и концепцию .NET. Объективно, по мнению многих авторитетных экспертов, да и в курилках разработчиков, «C#» сексуальнее Java, хотя, конечно, пока еще, несмотря на Mono, сильно привязан к Microsoft со всеми втекающими и вытекающими :-)
Scala, несомненно, большой шаг вперед, т.к. язык, конечно, получился научно-заумный и навороченный, взявший немало полезных и бесполезных вещей из мира функционального программирования. Но вот с популярностью что-то как-то не очень понятно. Однако Apache Spark [4] действительно хорош и популярен, нечего сказать.
Kotlin же популярен, т.к. делает Java более эффективной и простой для начинающих разработчиков, особенно на мобильных платформах, у которых нет времени серьезно изучать программирование :-)
Но основная проблема и в C# (на платформе .NET), а также в Scala, Kotlin и в других JVM-языках — осталась. Сборщик мусора, Карл, создающий заметную нагрузку на сервер и остановки выполнения кода на секунды при нагрузках и прожорливые требования к оперативной памяти! И сколько еще языков со сборщиком мусора и jit-компиляцией не придумают, указанные проблемы останутся и надежды пока нет, даже в теории.
«А как же PHP?». Да, сейчас поговорим про скриптинг. Казалось бы, зачем он? Примерно в конце 80-х стало очевидно, что, если нужно быстро решить задачу с помощью кода, не обязательно супербыстрого, причем безопасно, без неопределенного поведения и низкоуровневых дырок, можно написать скрипт. Скрипты писали и раньше, на bash, perl, awk, но, оказалось, что на python можно писать большие-пребольшие скрипты, особенно научные, причем годами!
Lua нашел свою нишу в геймдеве и машинном обучении (Torch [5]), JavaScript — в веб-разработке как на стороне браузера, так и на стороне сервера [6] (все же знают, что «npm» в Node.js написан на «rust»?). Python — в машинном обучении и анализе данных, а также в системном скриптинге. А PHP — прекрасно справляется с серверными задачами по веб-разработке.

Плюсы скриптинга очевидны:
Однако нельзя не знать потенциальных минусов скриптинга:
Однако, т.к. в большинстве бизнес-приложений, в т.ч. системах управления сайтами, CRM и т.п. большая часть времени выполнения кода тратится на запросы в базу данных, то преимущество jit Java/C# глубоко нивелируется скоростью написания решений на PHP/python/JavaScript и лично я, для создания веб-приложений, выберу 10-20 строк на PHP, чем 10 000 строк и кучу потрохов на Java/Spring. А PHP7 как-то разогнали так, что он работает быстрее python3 ;-)
Какой вывод можно тут сделать? Не нужно все задачи решать, как сейчас популярно, только скриптингом — в некоторых случаях разумно взять другой, более подходящий инструмент, если на это есть весомые причины:
Часто в компании мы практикуем такой подход:
Поэтому лучше начинать, как правило, со скриптинга, запускаться в бой, а дальше, если прямо-прямо нужно, подбирать другие инструменты и это проходит, обычно, очень гладко и без рисков.
Многие, за целую карьеру разработчика, так и не приходят сюда, а вот зря. Крайне полезно понять, почему появилось ФП (функциональное программирование) и почему в некоторых областях оно так популярно.
Объясню просто. Есть в математике такая нерешаемая проблема, как «halting problem» [7]. Если изложить очень простыми словами и совсем нестрого, зато понятно, то нельзя придумать алгоритм, доказывающий, что программа будет работать без багов. Почему? Потому-что изначально люди начали программировать агрессивно и императивно, используя:
И стали ошибаться. Мы видим это сейчас, наблюдая огромное количество багов как в вебе, так и в десктопных и мобильных приложениях. И как ни покрывай автотестами код, баги все равно продолжают просачиваться, разбегаться по полу и хихикать.
Чтобы остановить этот кошмар наступления глючного и беспощадного софта, еще в конце 50-х появилось направление функционального программирования и язык Лисп [8]. Сейчас же это семейство языков представляет, более-менее адекватно — Haskell [9].
Несмотря на то, что огромное количество возможных ошибок в коде действительно устраняется за счет:
Haskell откровенно не взлетел по причине агрессивных «понтов» — чтобы хорошо понять его терминологию, нужно быть, как минимум, кандидатом наук со специализацией в области одной из лидирующих теорий в современной математике: теории категорий [14]. А еще в Haskell явно намудрили с «ленивостью», то ли граф выполнения память переполнил, то ли выполнение началось, и память кончилась потом, что нередко больно бьет по его боевому применению. Именно поэтому солдаты в бою на территории противника бросают Haskell и берут автомат Калашникова.
И, конечно, совсем забыли про сборщик мусора — в Haskell он, к сожалению, тоже есть, что ставит его по эффективности и производительности на одну ступень с конкурентами типа Java/C#.
Но это не означает, что язык не нужно учить. Haskell развивает программисту, в первую очередь, , так нужные для написания ясных, эффективных и легко поддерживаемых годами программ. Известно ведь, что кроме скриптинга крайне полезно знать хоть один из «настоящих» языков программирования — и Haskell тут очень достойный кандидат.
Системное программирование, еще в начале нулевых, реализовывало себя в основном через C/C++ (возможно, нельзя не упомянуть в этом контексте и знаменитый Forth). А мнение [16] Линуса Торвальдса про C++ как тогда, так и сейчас не утратило своей актуальности, несмотря на попытки великого и ужасного Андрея Александреску изменить ситуацию в D [17] (со сборщиком мусора — ну как же так, опять наступили на эти грабли).
Однако, видимо людям надоело постоянно заниматься системным садо-мазохизмом и писать на С/C++ в рыцарских доспехах c парадигмой RAII [18] и кучей ограничений и запретов, изначально доступных в языке и библиотеках. И вот в конце 2009 в недрах Google появляется язык Golang [19].
Если быть честным и откровенным, то Golang особо ничего нового не принес в мир системного программирования, а, скорее, был сделан шаг назад и кувырок в бок. Golang представляется как урезанная по всем направлениям до минимума Java/C# (ООП порезано и упрощено до неузнаваемости) и да, со сборщиком мусора [20]… Единственные утешения, идущее от Golang:
И совсем мутная ситуация с пакетным менеджером. Даже в Node.js и python он есть.
Возможно, Golang был создан в рамках конкурентной борьбы крупных корпораций, Google vs Sun/Oracle, за сердца разработчиков, но мы этого, скорее всего, никогда не узнаем :-) Очевидно, что создание «сильно упрощенной Java/C#» привлечет и уже привлекает толпы поклонников решения системных задач, но выиграет ли от этого индустрия — нам еще предстоит увидеть. Хотя Docker на Golang вот уже появился и перевернул мир в верном направлении. А еще объективная польза от Golang — это язык с низким уровнем вхождения и если нет времени изучать Java/C#, а нужно решить системную задачу, то самое то.

Интересно на этом фоне смотрится, конечно, Swift [21], c «более продвинутым» сборщиком мусора и свежими идеями. Но не всегда же разрабатывать под macOS.
Мы же взрослые люди, умеем читать между строк и понимаем, что последние 40-50 лет постоянно предпринимались попытки создать быстрый, безопасный, строгий и системный или близкий к системному язык программирования, желательно с «zero-cost» абстракциями, но, что-то не очень-то получается :-) То язык получается относительно строгий, но, откровенно иногда тормозящий (Java/C#), то очень быстрый, но безнадежно дырявый (C/C++), то еще какой-то, но с цепочкой и гирей на левой ноге — сборщиком мусора. Ну нельзя что ли хорошенько подумать и написать компилятор, который МОЖЕТ ВСЁ вышеперечисленное ОДНОВРЕМЕННО?
Оказывается — можно. Чудо и, наверно, лучшее, что произошло за последние 50 лет в области создания инструментов программирования, случилось в середине 2010 года в Mozilla Research. Коллеги создали компилятор, который обладает следующими возможностями:
Уверен, вы ощутили шок, как и я когда-то. Как такое может быть? Это невозможно! Как соединили несоединимое и впихнули невпикуемое, что не удавалось сделать за последние 50 лет. Оказалось, возможно, «просто» обобщили ошибки предыдущих языков, написали действительно грамотный и пессимистичный компилятор и ввели в обиход несколько не встречавшихся раньше в программировании, уникальных концепций.
Rust можно представить как «легкий» и, разумеется, очень строгий и мощный по своей сути Haskell для системного программирования.
Еще Rust оказался более безопасным языком, чем, внимание, Java :-) — нет Nulls, алгебраические типы данных и pattern-matching по ним, строгие и мощные generics и traits и действительно безопасное многопоточное программирование. Вот это точно никто не ожидал. И код быстрее получается, и ресурсов меньше ест, и ошибок в коде меньше по причине очень строгого, «похожего на Haskell», компилятора и НЕТ СБОРЩИКА МУСОРА.
Теперь кратко обо всем по порядку.
А вот так! Память в компиляторе начали представлять как ресурс, «владеть» («ownership») которым может одна и только одна переменная. Если переменная выходит из области видимости, компилятор вставляет вызов деструктора [25] (деструктора может не быть, тогда ничего не вызывается).
Если переменная передается в функцию/метод, то владение передается туда и в конце функции деструктор будет вызван компилятором. Если переменная возвращается из функции/метода, то владение тоже возвращается на уровень выше и деструктор вызывается на уровне выше.
Таким простым способом раз и навсегда избавились от страшной мути в C++, связанной с конструкторами-копировщиками и move-семантики. Если описание показалось сложным, попробуйте написать код с деструкторами в rust и вы увидите, что все очень строго и логично.
В языке нет навороченного ООП и наследования, но есть мощные и гибкие traits, а также средства инкапсуляции. В этом язык, конечно, похож на Golang. Все крутится вокруг структур и методов на них, но, из-за алгебраических типов данных и pattern-matching, код получается точным и строгим (что забыли добавить в Golang, к сожалению). На структуру/данные можно создать ссылку на чтение и ссылку на запись. Но одновременно может быть создан только один тип: одна ссылка на запись или много ссылок на чтение. В терминологии языка это называется заимствование [26] («borrowing»). Это позволяет снизить необходимость копировать объекты, а также избежать гонки данных (за счет «read-write locks», реализуемых заимствованиями). Все это, внимание, строго проверяет компилятор и если код не компилируется, значит нужно его поправить и доказать пессимистичному компилятору, что ошибок больше нет.
Для работы со строками и другими операциями используются низкоуровневые типы slice [27], что служит, конечно, скорости. Однако есть проблема — строки устроены «немного сложно» и, похоже, они сами появились в языке вне воли разработчиков в результате мутации компилятора; но они работают, работают быстро и предсказуемо и на этом со строками пока все.
Язык очень сбалансировано напичкан возможностями функционального программирования:
В целом понятно, что все сложные и противоречивые концепции системного и многопоточного программирования (освобождение памяти, гонки данных) переложили на систему уникальных аффинных типов [31] со строгими гарантиями компилятора и оно… работает. Строгая система типов и суровая алгебра логики в сочетании с умным компилятором дают вам гарантии получения безопасного/многопоточного кода, работающего со скоростью C/C++ и потребляющего так же мало ресурсов. Причем изначально никто в это не верил.
За счет описанных выше уникальных для языка и встроенных в компилятор возможностей владения и заимствования, не возникает проблем с порядком установки-снятия блокировок, а многопоточное программирование делается как-то легко и без сюрпризов. Если что-то не так, код просто не компилируется. Я не буду описывать детали трейтов Sync/Send, это нужно увидеть вживую, но ничего сложного и мистического не происходит: реализуете логику, если компилятор ругается, исправляете, вот и всё.
Если хочется реализовать многопоточный сетевой сервис с неблокирующими соединениями, обрабатывающий десятки тысяч сокетов одновременно почти незаметно для процессора, можно взять готовую библиотеку и за 1-2 часа реализовать самые смелые мысли по работе с futures в функционально строгом стиле [32]. Получаем тоже самое, что внутри Node.js и python с async/await, но с гарантией строгих алгебраических типов, работающее гораздо быстрее и с на порядки меньшим потреблением ресурсов. А если результат одинаковый, зачем же платить больше?
Удивительно, но об этом тоже подумали и возможность написания unit и интеграционных тестов встроена в среду разработки и инструменты по умолчанию. Сразу пишешь к коду тесты [33] и они выполняются.
Приводя аналогию из Java, «Maven под именем cargo [23]» уже встроен в среду разработки, описываются зависимости и дальше магия: качаются исходники, компилируются и все работает. Удобно, кстати, полазать по исходникам, иногда очень помогает.
По умолчанию, память для структур и объектов выделяется в стеке, однако очень легко ее выделить и потом автоматически освободить в heap. Память, как уже описано выше, автоматически освобождается при выходе ее владельца (ссылающейся переменной) из области видимости. А если очень нужно, умные указатели разных видов тоже есть [34] (здравствуй Swift). Если написанное выше показалось сложным, то это не так — напишите код, выделяющий память в heap и выведите в деструкторе сообщение об освобождении памяти и все станет ясно и понятно. Подвохов никаких нет — память всегда будет освобождена и проверяет это не программист, а компилятор и еще гарантию дает.
На самом деле видно, что действительно получилось создать умный, сбалансированный, очень строгий и быстрый язык для безопасного системного программирования. Да, он еще молод (2 года как стабилизировался) и в библиотеках еще не все, говорят, есть, хотя я нашел все что нужно, от скоростной неблокирующей обработки сетевых сокетов [32], парсинга [35] аргументов командной строки и подключения к AmazonWebServices [36] до углубленной криптографии c tls/ssl, которую пришлось немного под задачу доработать и это не вызвало никаких проблем.
Однако, некоторые вещи, которые, к счастью, встречаются в реальный задачах очень редко, все-таки потребуют углубленного изучения. К таким особенностям я бы отнес понятие областей видимости («lifetimes») [37] и их использования.
Еще, пока видимо не очень прямо удобным местом является малое количество сред разработки. Неплохо ведет себя IntelliJ с модулем для rust [38], но иногда не справляется с подсказкой сложных типов. Однако можно писать и в Notepad++ — умный компилятор с гарантиями предупредит вас о ошибках в коде.

Поймите еще раз — чтобы овладеть технологией, нужно на ней начать писать полезный для компании код. Компилятор Rust настолько умен, что дает гарантии (на самом деле это очень важно, так не умеет делать компилятор C++) и не скомпилирует опасный/повреждающий память код, поэтому экспериментируйте сколько хотите — и код получите быстрый и безопасный и еще лучше станете программировать :-)
Раскрою немного детали проекта. В очередь Amazon SQS льются сотни пакетов данных в секунду. Очередь читается, разбирается воркерами локально, каждое сообщение обрабатывается брокером и перенаправляется на другой, внешний сервер. Внешних серверов — несколько. Изначально решение было реализовано через скриптинг: скрипт, занимая процесс в операционной системе, читал сообщения, обрабатывал и пересылал по сети. На нескольких мощных железных серверах (по 8 ядер, 16 ГБ ОЗУ) были запущены сотни скриптов, параллельно читающих из SQS, обрабатывающих и пересылающих данные. Просто, надежно, но потребление железа начало надоедать.
На Rust использовали преимущественно стандартные библиотеки и модули из cargo:
Без использования «unsafe» блоков и «std::mem::transmute», к сожалению, не обошлось — в стандартной библиотеке не удалось найти инструментов для парсинга бинарных данных в деревья.
Основной, если можно так его назвать, «затык» случился в компиляции — библиотеки не собирались на CentOS6 по причине «устаревшего ассемблера» в binutils, но на CentOS7 никаких проблем не возникло.
Общее впечатление — разработка на Rust напоминает, скорее «строгий скриптинг», чем системное программирование, не особо дольше скриптинга или веб-разработки как по ресурсам, так и по тестированию. При этом — строгая статическая компиляция, отсутствие сборщика мусора и алгебраически типы данных.
Общее ощущение — очень положительные. Еще бы, вместо нескольких железных серверов (8 ядер, 16 ГБ ОЗУ), задача стала решаться одним процессом (с десятками потоков), кушающим не более 5 ГБ ОЗУ и создающим не очень заметную нагрузку на ядра, при трафике в районе 0.5-1 гигабит.
Ну вот и закончился длинный, но, очень надеюсь, вдохновляющий и полезный пост про эффективную технологию. Теперь вы знаете еще один инструмент и более смело сможете им воспользоваться при необходимости. Мы обозрели историю развития языков программирования, их возможности и особенности и, возможно, сделали или сделаем правильные выводы. Удачи вам в проектах и хорошего, нет, отличного настроения!
P.S.:
* — да, чуть не забыл. Нужно, конечно, рассказать о блоке «unsafe». В этом блоке можно:
Т.е. в блоке «unsafe» нельзя заниматься произвольным развратом, доступным в C — а только cтрого определенными [29] видами опасных активностей. Поэтому можно и нужно спать спокойно :-)
Автор: AlexSerbul
Источник [42]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/338045
Ссылки в тексте:
[1] GNU: https://www.gnu.org
[2] Optional: https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html
[3] популярный и востребованный: https://www.rust-lang.org/production
[4] Apache Spark: https://ru.wikipedia.org/wiki/Apache_Spark
[5] Torch: http://torch.ch
[6] сервера: https://ru.wikipedia.org/wiki/Node.js
[7] «halting problem»: https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D0%B0_%D0%BE%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B8
[8] Лисп: https://ru.wikipedia.org/wiki/%D0%9B%D0%B8%D1%81%D0%BF
[9] Haskell: https://ru.wikipedia.org/wiki/Haskell
[10] алгебраических типов данных: https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%B5%D0%B1%D1%80%D0%B0%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B9_%D1%82%D0%B8%D0%BF_%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85
[11] можно найти: https://wiki.haskell.org/Mutable_variable
[12] Хиндли-Милнера: https://ru.wikipedia.org/wiki/%D0%92%D1%8B%D0%B2%D0%BE%D0%B4_%D1%82%D0%B8%D0%BF%D0%BE%D0%B2#%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B8%D0%BD%D0%B4%D0%BB%D0%B8_%E2%80%94_%D0%9C%D0%B8%D0%BB%D0%BD%D0%B5%D1%80%D0%B0
[13] частичного применения: https://wiki.haskell.org/Currying
[14] теории категорий: https://en.wikipedia.org/wiki/Category_theory
[15] мозги: http://www.braintools.ru
[16] А мнение: https://losst.ru/pochemu-linus-torvalds-ne-lyubit-c
[17] изменить ситуацию в D: https://wiki.dlang.org/Language_History_and_Future
[18] RAII: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%BB%D1%83%D1%87%D0%B5%D0%BD%D0%B8%D0%B5_%D1%80%D0%B5%D1%81%D1%83%D1%80%D1%81%D0%B0_%D0%B5%D1%81%D1%82%D1%8C_%D0%B8%D0%BD%D0%B8%D1%86%D0%B8%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F
[19] Golang: https://en.wikipedia.org/wiki/Go_(programming_language)
[20] сборщиком мусора: https://stackoverflow.com/questions/7823725/what-kind-of-garbage-collection-does-go-use
[21] Swift: https://oxozle.com/2017/05/10/sravnenie-arc-i-garbage-collector/
[22] преобразуются: https://doc.rust-lang.org/stable/book/ch13-00-functional-features.html
[23] cargo: https://doc.rust-lang.org/stable/cargo/
[24] Великолепный: https://doc.rust-lang.org/stable/book/ch19-06-macros.html
[25] вставляет вызов деструктора: https://doc.rust-lang.org/stable/book/ch04-01-what-is-ownership.html
[26] заимствование: https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html
[27] slice: https://doc.rust-lang.org/stable/book/ch04-03-slices.html
[28] доступны только для чтения: https://doc.rust-lang.org/stable/book/ch03-01-variables-and-mutability.html
[29] не рекомендуемая техника: https://doc.rust-lang.org/stable/book/ch19-01-unsafe-rust.html
[30] быстрый машинный код: https://doc.rust-lang.org/stable/book/ch13-04-performance.html
[31] аффинных типов: https://en.wikipedia.org/wiki/Substructural_type_system#Affine_type_systems
[32] функционально строгом стиле: https://tokio.rs
[33] Сразу пишешь к коду тесты: https://doc.rust-lang.org/stable/book/ch11-00-testing.html
[34] тоже есть: https://doc.rust-lang.org/stable/book/ch15-00-smart-pointers.html
[35] парсинга: https://rust-lang-nursery.github.io/rust-cookbook/cli/arguments.html
[36] AmazonWebServices: https://lib.rs/crates/rusoto_sqs
[37] областей видимости («lifetimes»): https://doc.rust-lang.org/stable/book/ch10-03-lifetime-syntax.html
[38] с модулем для rust: https://intellij-rust.github.io
[39] Rust book: https://doc.rust-lang.org/stable/book/title-page.html
[40] Rust cookbook: https://rust-lang-nursery.github.io/rust-cookbook/
[41] Rustonimicon: https://doc.rust-lang.org/stable/nomicon/
[42] Источник: https://habr.com/ru/post/477342/?utm_campaign=477342&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.