Уже сейчас вы могли обратить внимание на то, что синтаксис рассматриваемого языка программирования очень похож на синтаксис таких языков, как C/C++, ведь в обоих случаях для выделения комментариев используются два слэша, блоки кода обрамляются фигурными скобками, а аргументы функций - круглыми скобками. Также следует помнить о том, что для объявления функций используется ключевое слово fn , причем каждая программа должна иметь функцию main() . Восклицательный знак после имени функции println в данном случае указывает на то, что используется макрос (по сути, это удобная обертка над функцией print из библиотеки времени исполнения Rust).

Для компиляции программы следует просто выполнить команду:

Rustc hello.rs

В результате в директории с файлом исходного кода программы должен появиться бинарный файл с именем hello , для исполнения которого достаточно выполнить команду./hello . Но если вы обратите внимание на размер этого файла, вы будете в некоторой степени шокированы: он будет превышать 800 КБ. И все это нужно для работы такой простой программы? Ну, по умолчанию компилятор Rust осуществляет статическое связывание большей части библиотек времени исполнения с программой, поэтому вы можете скопировать бинарный файл в систему, в которой не установлено библиотек времени исполнения Rust и запустить его без каких-либо проблем. Однако, вы также можете сообщить компилятору о необходимости выполнения оптимизаций и динамического связывания:

Rustc -O C prefer-dynamic hello.rs

Теперь вы получите бинарный файл более приемлемого размера, равного 8 КБ, но в случае использования утилиты ldd вы обнаружите, что для корректной работы программы требуется наличие в системе динамической библиотеки libstd-<версия>.so .

Синтаксис языка программирования

Теперь, когда мы можем компилировать и запускать программы на Rust, я предлагаю разобраться с синтаксисом данного языка программирования и особо выделить его отличия от синтаксиса таких языков программирования, как C, C++ и других аналогичных:

Fn doubler (x: i32) -> i32 { x * 2 } fn main () { let a: i32 = 5; let b; b = doubler(a); println!("a, умноженное на 2 {}", b); match b { 1 ... 10 => println!("От 1 до 10"), _ => println!("Другое число"), } }

Если вы привыкли работать с языками C/C++, вы можете подумать, что данный код является каким-то странным, но он вполне логичен. Давайте начнем рассмотрение с функции main() : в первой строке let мы объявляем 32-битную целочисленную переменную a и присваиваем ей начальное значение 5. Мы могли бы пропустить указание типа переменной (i32 является стандартным типом переменных), а также не присваивать ей начальное значение, причем в этом случае она содержала бы нулевое значение. Обратите внимание на то, что при объявлении переменной и присваивании ей определенного значения таким же образом, как в случае переменной a из примера, вы не сможете впоследствии изменить ее значение, поэтому при компиляции следующего фрагмента кода будет сгенерировано сообщение об ошибке:

Let a: i32 = 5; a = 10;

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

Let mut a: i32 = 5;

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

Далее мы вызываем нашу функцию doubler с переменной a в качестве аргумента и сохраняем возвращаемое значение в переменной b . Обратите внимание на объявление функции doubler , которое находится в начале кода программы: в нем указывается тип параметра функции (i32) и тип возвращаемого значения (i32) после символов ->. Также несложно заметить, что в рамках функции выполняется единственная операция x * 2 , после которой даже не следует символа точки с запятой, как в обычном блоке кода на языке Rust; что же происходит там?

Оказывается, вы можете вернуть значение функции либо таким же образом, как в языке C, либо просто разместив выражение в последней строке кода функции, как было сделано в данном случае. И, ввиду того, что это всего лишь выражение, после него не нужно ставить точку с запятой.

Вернемся в функцию main() , в которой мы использовали макрос println!() для вывода результата; обратите внимание на методику подстановки значения переменной с помощью последовательности символов {} . Наконец, в примере демонстрируется чрезвычайно полезное ключевое слово "match" языка программирования Rust, которое позволяет значительно сократить объем кода в том случае, если вам необходимо выполнить большое количество операций if/else. В данном случае 1 … 10 является объявлением диапазона значений (от 1 до 10 включительно), а символ подчеркивания (_) соответствует всем остальным значениям.

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

Let x = (1, 2.0, "Hello");

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

Println!("{}", x.2);

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

Fn switch(input: (i32, i32)) -> (i32, i32) { (input.1, input.0) } fn main() { let x = (10, 50); let y = switch(x); println!("{}, {}", y.0, y.1); }

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

В рамках функции main() создается кортеж с именем x , содержащий значения 10 и 50, а также кортеж с именем y , содержащий значения, которые были возвращены после вызова функции switch() . Далее осуществляется простой вывод значений кортежа на экран (50, 10).

Совет: Если вам не терпится самостоятельно разобраться с возможностями Rust, рекомендуем начать с чтения официальной документации, расположенной по адресу https://doc.rust-lang.org/book .

Это было краткое описание синтаксиса и возможностей языка программирования Rust; если вы желаете узнать больше о данном языке программирования из специальной серии статей, дайте нам знать об этом!


Нам очень понравилась статья "Критика языка Rust и почему C/C++ никогда не умрет". Мы предложили автору, что выполним перевод статьи на английский язык, а также опубликовать её в нашем блоге. Он согласился, и мы с удовольствием представляем эту статью на русском и английском языке. Оригинал статьи находится .

Оригинал статьи размещён (текст на русском языке). Статья опубликована в нашем блоге с соглашения автора.

Примечание : Ниже по тексту я исхожу из предположения, что Rust является попыткой сделать быстрый и безопасный язык. В конце концов, ребята из Mozilla делали его, как инструмент разработки браузерного движка . Если же это очередной просто безопасный язык, тогда получаем странное. Самых разных безопасных языков и так уже пруд пруди, каждый найдет себе по вкусу. И если не стоит цели заменить C++, то (1) для чего в языке сделано unsafe подмножество? (2) зачем было удалять из языка легковесные потоки , удобно же? Другими словами, в этом случае происходящее вообще не имеет никакого смысла.

Если вдруг вы почитываете форум linux.org.ru, отмечу, это это не тот список из 10 чисто технических причин не любить Rust , речь о котором шла в этом трэде . Как показало обсуждение в Skype с уважаемым товарищем @sum3rman , есть больше одного мнения касательно того, насколько "техническими" считать эти причины. В общем, фиговый список я составил, но кое-какие пункты из него, наиболее интересные, пожалуй, я все-таки рискну привести. На самом деле, тут и простых, не технических, причин за глаза хватает.

То, что C/C++ в обозримом будущем никуда не денутся, и так любому трезво мыслящему человеку понятно. Никто не станет переписывать почти все десктопные приложения, ядра операционных систем, компиляторы, игровые и браузерные движки, виртуальные машины, базы данных, архиваторы, аудио- и видеокодеки, тонны прочих сишных библиотек, и так далее. Это очень-очень много быстрого, отлаженного, проверенного временем кода. Переписывать его очень-очень дорого, рискованно, и если честно, не лишено смысла только в искаженном сознании только самых упоротых Rust"оманов. Спрос на C/C++ программистов был и будет велик еще очень долго.

Хорошо, а как на счет применения Rust при написании нового кода?

Вспомним, что это уже далеко не первая попытка сделать "более правильный" C/C++. Возьмем хотя бы язык D. Появился в 2001 году, очень хороший язык. Нет ни вакансий, ни нормальных инструментов разработки, ни каких-то особо выдающихся саксесс сторис. Проект OpenMW изначально писали на D, а потом внезапно решили целиком переписать на C++ . Как признаются разработчики, им приходило много писем в стиле "отличный проект, мы были бы рады в него контрибьютить, но не знаем и не хотим знать этот дурацкий D". Википедия сообщает, что помимо D была и масса других попыток в той или иной степени убить C++, например, Vala , Cyclone, Limbo, BitC. Многие ли вообще слышали о таких языках?

Думаю, давно пора извлечь уроки из истории. Ни один здравомыслящий человек не потащит в проект новый язык, пока вы хотя бы не покажете ему нормальные инструменты разработки, не расскажете парочку саксесс сторис и не покажете десяток программистов на этом языке, живущих поблизости. Программисты же, пожалуй, кроме самых молодых, никогда не станут тратить свое время и здоровье на изучение очередного самого правильного языка, пока вы не покажете им нормальные инструменты разработки (не поделки типа Racer), пару десятков тысяч готовых библиотек (не "experimental", "unstable" и так далее), не расскажете парочку саксесс сторис и не покажите десяток открытых вакансий в их городе. Проблема курицы и яйца. Очень редко эту проблему удается успешно решить (условно тут можно привести в пример и Scala), в основном благодаря вложению времени и денег со стороны некоторой крупной компании (Google, Typesafe), по каким-то своим соображениям заинтересованных в популяризации языка.

Как я уже отмечал, одних только не технических причин более, чем достаточно. Однако чисто из любопытства попробуем представить на секунду, что их нет. Тогда нет причин не писать на Rust? Оказывается, это тоже как минимум под очень большим вопросом.

C/C++ критикуют за разное. Критикуют, кстати, очень часто те, кто в продакшене даже издали не видел кода на С++. Коротко и ясно проблему можно описать так: С++ очень быстрый (а также не требовательный к памяти, заряду батареи и тд), но не безопасный в том смысле, что позволяет выходить за границы массивов, по ошибке обращаться к освобожденным кускам памяти и так далее. В свое время эта проблема привела к появлению массы безопасных языков, таких, как Java, C#, Python и других. Но оказалось, что эти языки по сравнению с C++ слишком требовательны к ресурсам и обладают прочими недостатками, вспомним хотя бы неизбежный stop the world при сборке мусора. Поэтому люди бьются над задачей сделать язык такой же быстрый, как C++, но еще и безопасный. Одним из таких языков и является Rust.

Rust действительно безопасный, но, к сожалению, далеко не быстрый. По скорости на момент написания этих строк Rust сравним с Java, Go и Haskell:

Я искренне надеюсь, что со временем его как-то разгонят, но до тех пор в плане компромисса скорости и безопасности он не намного интереснее Scala или Go. До сих пор остается открытым вопрос, можно ли вообще сделать язык быстрым и безопасным, или постоянные проверки на выход за границы массива, безопасные обвязки вокруг биндингов к сишным библиотекам и так далее автоматически делают любой язык в 2 раза медленнее С/C++.

А за счет чего, собственно, Rust безопасен? Если говорить простыми словами, то это язык со встроенным статическим анализатором кода. Действительно очень крутым статическим анализатором, который ловит все типичные для С++ ошибки, притом не только связанные с управлением памятью, но и многопоточностью . Передал по каналу ссылку на изменяемый объект другому потоку, а потом попробовал воспользоваться этой ссылкой сам - все, не скомпилится. Это действительно здорово.

Часто приводится аргумент, что 90% времени выполняется только 10% кода (что, насколько я понимаю, чисто эмпирическое правило - быстро найти строгих исследований на эту тему не удалось). Следовательно, бОльшую часть программы можно написать на безопасном Rust, а 10% "горячего" кода - на его unsafe подмножестве, и медленность текущей реализации Rust на самом деле не представляет собой проблемы. Ок, но тогда получается, что Rust вообще не нужен, потому что я могу написать 90% кода на Go, а 10% на Си. Только искатели серебряных пуль и оторванные от реальности те-еретики будут использовать Rust исключительно из соображений, что 100% программы можно написать как бы на одном языке. Хотя в действительности это два диалекта одного языка, что не так уж сильно отличается от связки Java плюс Си или Go плюс Си.

На самом деле, правило 10:90 - это все равно вранье. По этой логике можно переписать 90% WebKit, 90% VirtualBox или 90% GCC на Java и получить такой же результат. Очевидно, это не так. Даже если дело не в том, что в ряде программ это отношение очень другое, то следите за руками. Допустим, вся программа написана на небезопасном C/C++ и время ее выполнения, условно говоря, равно 0.9*1 (малая часть горячего кода) + 0.1*1 (много холодного кода) = 1. Теперь сравним с программой на безопасном языке со вставками на Си: 0.9*1 + 0.1*2 = 1.1, условно 10% разницы. Это много или мало? Зависит от ваших масштабов. В случае с Google даже несколько процентов могут сэкономить миллионы долларов (см пункт 5 в пейпере, "Utilization"). Или представьте, что со следующим обновлением JVM внезапно начнет требовать на 10% больше ресурсов! Я боюсь даже гадать, сколько нулей будет в цифре, полученной после перевода процентов на американские деньги! 10% - это дофига в задачах, где используются Си и C++.

Мы повторяем "преждевременная оптимизация - корень всех зол", как мантру. Но если следовать ей буквально, то давайте повсюду использовать пузырьковую сортировку вместо quicksort. Мы же не знаем точно, что программа будет именно в этом месте тормозить! Какой смысл оборачивать обыкновенные счетчики каких-тод ействий в акторы или транзакционную память, если можно сразу воспользоваться более эффективным atomic? И вообще, в тривиальных случаях нет смысла принудительно инициализировать все-все-все переменные, делать кучу дополнительных проверок и так далее. Пусть в итоге мы получим не 10% ускорения, а 2-5%. Это ведь тоже совсем неплохо, если потребовало всего лишь пары лишних минут размышлений. И как мы уже выяснили, в задачах, решаемых на С/C++, это может быть большой разницей! Потом, кто сказал, что найти горячее место, переписать код (возможно, очень много кода) и доказать, что он стал действительно быстрее - это проще, чем подумать о производительности заранее?

Если отвлечься от вопроса компромисса скорости и безопасности, то по дизайну самого языка у меня тоже есть вопросы. В частности, касательно пяти типов указателей. С одной стороны, это неплохо, когда программист задумывается о том, где лежат переменные, в стеке или куче, и могут или не могут с ними одновременно работать несколько потоков. Но с другой, представьте, что вы пишите программу, и оказалось, что переменная должна жить не в стеке, а в куче. Вы переписываете все, чтобы использовался Box. Потому вы понимаете, что на самом деле нужен Rc или Arc. Снова переписываете. А потом еще раз переписываете на обычную переменную в стеке. Все это - без нормальной IDE под рукой. И регулярки не помогут. Ну или же просто в стиле "Vec>>>", привет, Java! Но что самое печальное, компилятор уже знает о времени жизни всех переменных, он мог бы выводить все эти Box, Arc и так далее автоматически. Но почему-то эта часть работы переложена на программиста. Намного удобнее было бы просто писать val (в третьем-то тысячелетии!), а там, где надо, явно указывать Box или Rc. Разработчики Rust в этом смысле запороли всю идею.

Из-за этого, в частности, сильно сужается область применения Rust. Никто в здравом уме не станет писать на таком языке веб и серверсайд. Особенно учитывая, что он не дает существенных преимуществ перед теми же языками под JVM. Да и Go с нормальными легковесными потоками (не футурами) для этих задач выглядит куда более привлекательнее. С футурами, чтобы не прострелить себе ногу, нужно еще научиться работать, а вы говорите "безопасный язык". Да, у этих языков свои особенности, взять все тот же stop the world, но эта проблема решаемая, как распиливанием на микросервисы , так и другими приемами . И да, никто не будет транслировать Rust в JavaScript, писать на нем скрипты для раскладки в AWS, или использовать в качестве языка запросов к MongoDB. Под Android тоже вряд ли писать будут, но по другой причине - там сильно больше одной архитектуры, с JVM намного проще. Если вы вдруг думали, что Rust "подходит для всех задач", вынужден вас огорчить.

Ну и до кучи:

  • Макросы, как подпорка к излишней многословности, вызванной отсутствием нормальных исключений. Я уже писал о проблемах метапрограммирования , в частности, нормальную IDE для Rust мы вряд ли увидим из-за него. И я не уверен, но похоже, что у макросов в Rust даже неймспейсов нет.
  • Люди идиоты, а cargo очень поощряет стягивание пакетов напрямую из git-репозиториев, в обход Crates.io. В итоге велика вероятность получить такой же бардак с пакетами, как и в мире Erlang с его Rabar"ом. К слову, в мире Go, похоже, такая же ситуация.
  • Как многие новые языки, Rust идет по пути упрощения. Я в целом понимаю, почему в нем нет нормального наследования и исключений, но сам факт, что кто-то за меня решает такие вещи, оставляет неприятный осадок. C++ не ограничивает программиста в вопросах чем пользоваться, а чем нет.
  • Если уж идти по пути упрощения, то выкинуть бы уж все эти расширения языка. А то получается, как в мире Haskell, каждый программист пишет на своем диалекте.
  • Смарт поинтеры, если что, далеко не бесплатны и не приводят к предсказуемому времени сборки мусора. Какому-то потоку внезапно выпадает честь освободить очень глубокую структуру данных. Пока он ходит по лабиринту из мертвых ссылок, зависящие от него потоки терпеливо тупят. Та же проблема есть и в Erlang с его маленькими кучками, сам не раз наблюдал. Смарт поинтеры имеют и свои проблемы, ту же фрагменатцию памяти и утечки. Забыл викпоинтер в цеклической структуре, и все. И это в языке, претендующем на безопасность. Если хотите предсказуемого времени GC, либо изучайте поведение вашего приложения под нагрузкой, и предпринимайте меры (вспомним хотя бы те же пулы объектов), если время GC вас не устраивает, либо управляйте памятью вручную.
  • Кто-нибудь видел строгое описание семантики Rust? У него хотя бы memory model есть? Тоже мне "безопасный" язык, "доказывающий корректность" программ, который вообще-то может трактовать исходный код десятью разными способами, ха!
  • Не могу в очередной раз не напомнить, что проблема почти всегда в людях, а не в технологиях . Если у вас получается плохой код на C++ или Java вдруг тормозит, это не потому что технология плоха, а потому что вы не научились правильно ею пользоваться. Rust вы тоже будете недовольны, но уже по другим причинам. Не проще ли научиться пользоваться более популярными инструментами и начать их любить?

В общем и целом, ближайшие лет 5 я лучше будут инвестировать свое время в изучение C/C++, чем Rust. С++ - это промышленный стандарт . На этом языке успешно решают самые разнообразные задачи уже более 30 лет. А Rust и иже с ним - непонятные игрушки с туманным будущем. Про скорую смерть С++ разговоры идут как минимум с 2000-х, но писать на C/C++ за это время стали не меньше. Скорее наоборот. И мы видим, что язык развивается (C++11, C++14), для него появляются новые инструменты (вспомним хотя бы CLion и Clang), и соответствующих вакансий просто куча.

Программист на C++ всегда без труда найдет себе работу с более чем достойной зарплатой , а при необходимости быстро переучится на Rust. Обратное очень и очень сомнительно. Кстати, язык, если что - далеко не единственный и не решающий фактор при выборе нового места работы. Кроме того, опытный программист на C/C++ без труда вонзается в исходники PostgreSQL или ядра Linux, использует мощные современные инструменты разработки, а также имеет в своем распоряжении множество книг и статей (скажем, по OpenGL).

Берегите свое время и здоровье, их у вас не так много, как кажется!



На сегодняшний день синтаксис Rust поддерживается в vim и emacs с помощью поставляемых вместе с компилятором синтаксических файлов.
Имеются также синтаксические пакеты для популярного проприетарного редактора Sublime Text 2 и свободного редактора Kate. Поддержки Rust в IDE пока нет. Поддержка отладчиков, судя по всему, тоже отсутствует.

Вместе с компилятором rustc поставляются следующие утилиты:
> rustdoc - утилита для автоматической генерации документации из исходного кода наподобие Doxygen;
> rustpkg - менеджер пакетов, позволяющий легко устанавливать дополнительные пакеты и библиотеки;
> rusti - так называемая REPL-утилита (read-eval-print-loop). По сути это тестовый интерпретатор, который принимает выражение на Rust из командной строки, компилирует его во внутреннее представление LLVM, выполняет и выводит результат;
> rust - универсальная утилита, запускающая другие утилиты или компилятор в зависимости от параметров. У меня она так и не заработала.

Вся доступная документация по языку собрана на официальном сайте www.rust-lang.org. Имеется подробное руководство (http://static.rust-lang.org/doc/tutorial.html) - исчерпывающая формальная документация по всем нюансам синтаксиса, модели памяти, системе времени выполнения и т.п., а также документация по встроенной библиотеке core и стандартной библиотеке std. Вся документация англоязычная. На русском языке актуальных материалов нет, а пара имеющихся обзорных статей уже успели сильно устареть.

Идеология и синтаксис


Rust относится к Си-подобным языкам, использующим фигурные скобки для выделения блоков кода. Язык является «мультипарадигменным», т.е. позволяет писать код в императивно-процедурной, объектно-ориентированной, конкурентной или функциональной манере. Rust компилируется в нативный бинарный код на любой поддерживаемой платформе (использует LLVM в качестве бекэнда). В теории код на Rust не должен уступать в скорости коду на C/C++. Rust позиционируется как системный язык, однако в нем нет встроенной поддержи блоков кода на ассемблере как в «истинных» системных языках С, С++ или D.

Модель памяти Rust изначально не допускает появления нулевых или «висячих» указателей и переполнений буфера. Имеется опциональный сборщик мусора, работающий только в пределах одной нити кода. У языка есть встроенная поддержка легковесной многозадачности и коммуникаций между нитями с помощью обмена сообщениями. Разделяемой памяти (shared memory) в Rust не существует в принципе. Все переменные подразделяются на стековые, переменные кучи для данного потока, и переменные так называемой «обменной» кучи, которые могут читаться всеми потоками, но не могут ими изменяться. Это автоматически исключает «заклинивание» (deadlock), которое считается бичом многопоточного программирования. ABI языка совместим с Си, поэтому программы на Rust могут компоноваться с библиотеками, написанными на Си без дополнительных оберток. Для нужд низкоуровневого системного программирования и для обеспечения совместимости с Си в языке есть особый «небезопасный» режим без проверки корректности указателей. По своей идеологии Rust ближе всего к языку Go. Так же, как и в Go, основной акцент сделан на простоте многопоточного программирования и скорости разработки масштабных приложений, а синтаксис местами так же непривычен и в чем-то удивителен. В то же время Rust не настолько минималистичен, как Go, и претендует на роль системного языка.

Синтаксис Rust большей частью заимствован из С и С++ с примесью идей из языков Go, C#, Haskell, Python и Ruby. Не буду исчерпывающе описывать синтаксис языка, а остановлюсь только на наиболее интересных концепциях.



Здравствуйте, уважаемые читатели!

Жизнь не стоит на месте, и вот в «O"Reilly» задумались об издании первой фундаментальной книги о языке программирования Rust:

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

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

Дисклеймер: Вкус к языкам программирования – дело очень субъективное, как и этот пост. Воспринимайте его со здоровым скептицизмом .

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

Барьер при изучении Rust

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

  1. Язык стремительно меняется . В Rust нет «великодушного пожизненного диктатора». Язык развивается благодаря вкладу участников основной команды и сообщества.
  2. Учитывая первый пункт, учебные материалы по Rust очень скудны . Есть руководство , другая официальная документация и сайт Rust by Example – это отличные ресурсы. Однако Rust гораздо сложнее. Зачастую приходится штудировать RFC, блоги и даже комментарии на Github, чтобы отыскать нужную информацию, причем если даже эта информация появилась буквально вчера, все равно в ней нет полной уверенности. Жду хорошей, авторитетной книги по Rust, хотя, готов поспорить, она будет объемистой.
  3. Система владения и механизм проверки заимствования в Rust может смутить новичков . Для обеспечения безопасности памяти без сборки мусора в Rust задействуется затейливая система заимствования и владения. Зачастую она отпугивает неофитов.
  4. Компилятор Rust очень строгий . Я называю Rust дисциплинирующим языком. Все, что не является для компилятора Rust вполне очевидным, вы должны указывать самостоятельно, причем о некоторых своих намерениях вы и сами поначалу не догадываетесь. Этот барьер обучения, вкупе со всеми остальными, зачастую приводит к тому, что первое впечатление от Rust оказывается обескураживающим.

Достоинства

У Rust много достоинств. Некоторые из них уникальны.

Безопасность памяти без сборки мусора

Пожалуй, это наиважнейшее достижение Rust. В низкоуровневых языках программирования, допускающих непосредственную манипуляцию с памятью, такие ошибки, как использование освобожденной памяти (use-after-free) или утечки памяти во время исполнения довольно накладны. В современном языке C++ возможности борьбы с такими вещами улучшились, однако они предполагают строгую техническую дисциплину (читай: программисты продолжают выполнять небезопасные операции). Соответственно, на мой взгляд, в целом С++ не может принципиально и надежно решить эту проблему.

Действительно, Rust-программисты могут писать небезопасный код в блоке unsafe, но (1) это делается осознанно и (2) блоки unsafe могут составлять лишь очень малую долю всей базы кода, при этом они строго контролируются.
Сборщик мусора - самый обычный инструмент, обеспечивающий безопасность памяти. Если вы ладите с GC, то вариантов у вас не мало. Однако система владения, применяемая в Rust, обеспечивает не только безопасность памяти, но и безопасность данных и ресурсов (см. ниже)

RAII и ресурсы

RAII (получение ресурса есть инициализация) - странный термин, но хорошо передает заложенную в нем идею. В Википедии читаем, что RAII работает с объектами, выделяемыми в стеке. Система владения Rust позволяет применять этот принцип и с объектами, выделяемыми в куче. Благодаря этому автоматическое высвобождение ресурсов – например, памяти, файлов, сокетов - становится хорошо предсказуемым и гарантированным во время компиляции.
В динамических языках вроде Python или Ruby есть подобные возможности, но они не сравнятся по мощности с Rust IMO.

Конкурентность без гонок данных

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

Алгебраический тип данных

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

Композиция приоритетнее наследования

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

Недостатки (условные)

Все должно быть предельно четко

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

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

Сборка мусора вторична

В Rust есть простейший сборщик мусора: Rc, подсчет ссылок и Arc, атомарный подсчет ссылок без циклического обнаружения. Однако эти возможности не действуют в языке по умолчанию, и вам придется чаще использовать стандартные механизмы управления памятью в Rust (стек, & и Box). Если проблемы с памятью в вашем приложении несущественны, то вам придется потерпеть Rust-овскую модель безопасности памяти, где не применяется сборщик мусора.

Выразительность - не самоцель

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

Сравнительно высокий входной барьер

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

Rust и другие языки

Динамические языки

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

  • Быстрое прототипирование или одноразовые задачи
  • Код не для продакшена, либо такой, где ошибка во время исполнения - небольшая проблема
  • Собственный (индивидуальный) проект
  • Полуавтоматическая работа (напр. парсинг/анализ логов, пакетная обработка текста)

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

  • Работы в средней или крупной команде
  • Кода, ориентированного на долгосрочное использование в продакшене
  • Кода, который будет использоваться долго, предполагает регулярную поддержку и/или рефакторинг
  • Код, для обеспечения безопасности которого вы бы написали много модульных тестов

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

Go

Сравнение двух этих языков – отличный повод поспорить, но, поскольку я некоторое время изучал , все-таки поделюсь здесь моими субъективными впечатлениями о нем. По сравнению с Rust, вот что мне нравится в Go:

  • легковесность – язык маленький (и простой, при этом очень мощный)
  • утилита gofmt – значительно снижает умственную нагрузку при программировании
  • goroutine/channel
  • Мгновенная компиляция

Почему я завязал с Go:

  • Он слишком минималистичен. Система типов и сам язык не слишком расширяемы
  • Программирование на Go кажется мне немного сухим. Напоминает дни, когда я программировал на Java: хорошо подходит для корпоративной разработки, механистично и… не так интересно (напоминаю: о вкусах не спорят)
  • Популярность Go сохраняется благодаря поддержке Google, но это вызывает у меня некоторый скепсис. Когда интересы сообщества и компании не совпадают, первыми могут пожертвовать. Разумеется, любая компания преследует прежде всего собственные интересы. В этом нет ничего плохого. Это просто… немного раздражает. (Многие языки и фреймворки, продвигаемые корпорациями, сталкиваются с подобной проблемой. Mozilla хотя бы не зависит от биржевых котировок).

Nim

Nim (раньше назывался Nimrod) - очень интересный язык. Он компилируется в C, поэтому производительность у него весьма хорошая. Внешне он напоминает Python - язык, программировать на котором мне всегда нравилось. Это язык со сборкой мусора, однако в нем предоставляется мягкая поддержка в реальном времени, и само поведение сборщика мусора более предсказуемое. В нем интересная система эффектов. В принципе, этот язык мне очень нравится.

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

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

Прочие

Есть и другие языки вроде Julia и . Julia - динамический язык с хорошей производительностью и гладкими вызовами в стиле C. (Если вы любите динамические языки и REPL - обратите внимание). Julia привлек всеобщее внимание, благодаря своим числовым и научным полям. Хотя он и может стать языком общего назначения, мне кажется, что на развитие этого языка значительно влияет сообщество его зачинателей.

D, как минимум, изначально, представлял собой попытку создать «C++, только лучше». Его версия 1.0 вышла в 2007 году, поэтому данный язык не такой уж и новый. Это хороший язык, но по объективным причинам он до сих пор не прижился: дело и в расколе на Phobos/Tango на раннем этапе, и в обеспечении безопасности памяти в первую очередь через сборку мусора, и в изначальном позиционировании в качестве замены для C++.

Почему я считаю, что шансы у Rust довольно высоки

В наше время появляется так много новых языков программирования. Чем же, на мой взгляд, среди них выделяется Rust? Приведу следующие доводы:

Настоящий язык для системного программирования

Встраиваемость - нелегкая задача. Пожалуй, она решается буквально на нескольких языках, а то и всего на двух: C и C++. (Возможно, именно поэтому Skylight выбрала Rust для разработки расширения для Ruby, хотя это и было крайне рискованно.) Примечательно, насколько хорошо Rust удалось избавиться от издержек времени исполнения. Это открывает перед Rust уникальные перспективы.

Без Null

Null-объект/указатель (так называемая "ошибка на миллиард долларов ") - распространенный источник ошибок времени исполнения. Существует лишь несколько языков программирования, в которых отсутствует null, в основном это функциональные языки. Дело в том, что для избавления от null требуется очень продвинутая система типов. Как правило, чтобы справиться с этим на синтаксическом уровне языка, требуется алгебраический тип данных и сравнение с шаблоном.

Низкоуровневый язык с продвинутыми высокоуровневыми конструкциями

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

Сильное сообщество и практическая востребованность

Сообщество Rust очень дружелюбное и активное. (Разумеется, это субъективное впечатление). Кроме того, Rust использовался в некоторых серьезных практических проектах - речь, в частности, о компиляторе Rust, Servo , Skylight и т.д. еще на этапе разработки языка.

До сих пор - без крупных ошибок

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

Rust для веб-разработки

Если Rust – язык для системного программирования, подойдет ли он для веб-разработки? Я ищу ответ и на этот вопрос.

Библиотеки и фреймворки

В первую очередь, для этого должны быть готовы некоторые HTTP-библиотеки. (Об этом рассказано на сайте «Are we web yet»). Первая библиотека rust-http уже устарела; ее потенциальная наследница Teepee практически в анабиозе. К счастью, Hyper кажется хорошей кандидатурой. Она уже принята в Servo, симбиотическом проекте Rust, я расцениваю это как благословление на роль HTTP-библиотеки для Rust.

Стандартная библиотека Rust пока не поддерживает асинхронный ввод/вывод. Для этой цели можно использовать внешнюю библиотеку mio , обеспечивающую неблокирующий сокетный ввод/вывод. Поддержка зеленых потоков была упразднена в рамках упрощения I/O.

Активно разрабатывается несколько веб-фреймворков для Rust, в их числе - Iron и nickel.rs . Может потребоваться время, прежде чем ситуация с ними уляжется.

Rust – язык для веба?

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

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

Годится ли Rust для веб-стартапов?

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

Попробуйте Rust!

Вы можете помочь и перевести немного средств на развитие сайта



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

Что общего у Rust и других языков?

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

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

Уклон в сторону надёжности лучшим образом демонстрирует язык Haskell , который имеет компилируемую природу и обеспечивает высокие показатели безопасности. Всё, что можно компилировать, будет исправно работать. Главный недостаток - это низкая производительность, сложно представить проект, требующий высокой скорости написанный на Haskell .

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

Rust вобрал в себя лучшие характеристики C++ и Haskell , а также смог сохранить достаточную практичность и функциональность от остальных конкурентов.

В чем же прелесть языка Rust?

Волшебные характеристики Rust стали доступными при помощи основ компилирования и информации о сущности владельца (owner ), о программисте, который только временно отлаживает или занял проект (mutable borrow ), а также об обычном зрителе (immutable borrow ).

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

Этому языку необходим несколько отличающийся подход. Несмотря на непривычность, алгоритм достаточно очевидный и эффективный. Теперь мы определимся с основами языка, которые способны завести в тупик при начале изучения:

  1. Полностью устранена система наследования, для замены используется особая структура и способности, подробнее traits .
  2. Присутствуют указатели исключительно в коде, который не подвергается дополнительной защите, то есть внутри функции unsafe {} . Для их замены в безопасном коде используются ссылки, которые обеспечивают правильное указание на имеющиеся объекты.
  3. Если ссылка статическая и ведёт к определённому элементу, например, immutable borrow = &Object , до момента смерти ссылки она не может изменяться любым пользователем.
  4. При наличии изменяющейся ссылки mutable borrow = &mut Object , нельзя прочитать содержимое любому другому пользователю весь период жизни ссылки.
  5. Разработчики делают акцент на Mac и *nix платформы, из-за этого работать на системе Windows можно только с использованием среды GNU .

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

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

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

Следить за изменениями в языке программирования помогает постоянная рубрика «This Week in Rust », которую можно найти в Rust "n Stuffs по ссылке . Здесь всегда есть информация о предшествующих и прошедших изменениях, а также перспективах развития языка.