Вышел Rust 2018… но что это такое?

Автор оригинала: Lin Clark, The Rust Team
  • Перевод
Статья написана Лин Кларк в сотрудничестве с командой разработчиков Rust («мы» в тексте). Можете прочитать также сообщение в официальном блоге Rust.

6 декабря 2018 года вышла первая версия Rust 2018. В этом релизе мы сосредоточились на производительности, чтобы разработчики Rust стали работать максимально эффективно.


Временнáя шкала показывает переход функций из бета-версии в Rust 2018 и Rust 2015. Она окружена значками для инструментов и четырёх областей: WebAssembly, embedded, networking и CLI. Красный круг — эффективность разработчика — окружает всё, кроме Rust 2015

Но вообще непросто объяснить, что такое Rust 2018.

Некоторые представляют его новой версией языка… примерно так и есть, но не совсем. Я говорю «не совсем», потому что здесь «новая версия» означает не то, что новые версии других языков.

В большинстве других языков все новые функции добавляют новую версию. Предыдущая версия не обновляется.

Система Rust действует иначе. Это связано с тем, как развивается язык. Почти все новые функции на 100% совместимы с Rust. Они не требуют каких-либо изменений. Это означает, что нет причин ограничивать их кодом Rust 2018. Новые версии компилятора продолжат поддерживать “Rust 2015 mode” по умолчанию.

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

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

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

Таким образом, мы добавляем ключевые слова в Rust 2018. Хотя функция ещё не вышла, ключевые слова теперь зарезервированы. Все несовместимые изменения на ближайшие три года разработки (например, добавление новых ключевых слов), вносятся единовременно в Rust 1.31.



Хотя в Rust 2018 есть несовместимые изменения, это не значит, что ваш код сломается. Даже при наличии переменных async и await код будет компилироваться. По умолчанию компилятор работать как раньше.

Но если хотите использовать одну из новых функций, то можете выбрать новый режим компиляции Rust 2018. Команда cargo fix скажет, если нужно обновить код для использования новых функций и автоматизирует процесс внесения изменений. Затем можете добавить edition=2018 к своему Cargo.toml, если согласны на использование новых функций.

Этот спецификатор версии в Cargo.toml не применяется ко всему проекту и не относится к вашим зависимостям. Он ограничен одним конкретным крейтом. То есть можно одновременно использовать крейты Rust 2015 и Rust 2018.



Поэтому даже при использовании Rust 2018 всё выглядит примерно так же, как Rust 2015. Большинство изменений внедряются одновременно в Rust 2018 и Rust 2015. Только несколько функций требуют несовместимых изменений.



Rust 2018 — это не только изменения основного языка. Далеко не только они.

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

Таким образом, вы можете представлять Rust 2018 как спецификатор в Cargo.toml, который используется для включения нескольких функций, требующих несовместимых изменений…



Или вы можете представить его на момент времени, когда Rust становится одним из самых эффективных языков для многих применений — когда вам нужна производительность, эффективное использование ресурсов или высокая надёжность.



Мы предпочитаем второй вариант определения. Итак, давайте посмотрим на все усовершенствования, сделанные за пределами языка, а затем погрузимся в сам язык.

Rust для конкретных применений


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



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

Команда разработчиков Rust сформировала рабочие группы по четырём направлениям:

  • WebAssembly
  • Встраиваемые приложения
  • Сетевые задачи
  • Инструменты командной строки

WebAssembly


Для WebAssembly пришлось создать совершенно новый набор инструментов.

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



Rust хорошо подходит для веб-разработки по двум причинам:

  1. Экосистема крейтов Cargo работает так, как привыкло большинство разработчиков веб-приложений. Объединяете кучу небольших модулей, чтобы сформировать более крупное приложение. Это значит, что Rust легко использовать именно там, где нужно.
  2. Rust потребляет мало ресурсов и не требует среды выполнения. Не нужно много кода. Если у вас крошечный модуль, выполняющий много тяжёлой вычислительной работы, внедрите несколько строчек Rust, чтобы его ускорить.

С помощью крейтов web-sys и js-sys из кода Rust легко вызвать веб-API, такие как fetch или appendChild. И wasm-bindgen упрощает поддержку высокоуровневых типов данных, которые WebAssembly нативно не поддерживает.

После написания модуля Rust WebAssembly есть инструменты, чтобы легко подключить его к остальной части веб-приложения. Можете использовать wasm-pack, чтобы автоматически запустить эти инструменты, и запушить модуль в npm, если хотите.

Подробнее см. в книге «Rust и WebAssembly».

Что дальше?


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

Встраиваемые приложения


Для встроенной разработки необходимо было повысить стабильность существующей функциональности.

Теоретически, Rust всегда был хорошим языком для встроенных приложений. Это современный инструментарий, которого катастрофически не хватало разработчикам, и очень удобные языковые функции высокого уровня. Всё это без лишней нагрузки на CPU и память. Таким образом, Rust отлично подходит для embedded.

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



В итоге разработчики зависели от экспериментальной версии Rust. И в отсутствие автоматических тестов экспериментальная сборка часто не работала на микроконтроллерах.

Чтобы исправить это, разработчики постарались перенести все необходимые функции на стабильный канал, добавить тесты к системе CI для микроконтроллеров. Это означает, что изменение какого-нибудь десктопного компонента не сломает встроенную версию.

С такими изменениями разработка встроенных систем на Rust переходит из области передовых экспериментов в область нормальной эффективности.

Подробнее см. в книге «Rust для встроенных систем».

Что дальше?


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

Сетевые задачи


Для работы в сети необходимо было встроить в язык ключевую абстракцию: async/await. Таким образом, разработчики могут использовать стандартные идиомы Rust даже в асинхронном коде.

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

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

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

Ключевые слова для async/await реализованы в версии 1.31, хотя в настоящее время не поддерживаются реализацией. Бóльшая часть работы выполнена, и функция должна быть доступна в следующем релизе.

Что дальше?


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

Многие серверы выполняют рутинные задачи: анализируют URL или работают с HTTP. Если превратить их в компоненты — общие абстракции, которые совместно используются как крейты — тогда будет легко подключать их друг к другу, формируя всевозможные конфигурации серверов и фреймворков.

Для разработки и тестирования компонентов создан экспериментальный фреймворк Tide.

Инструменты командной строки


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

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

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

Rust не требует среды выполнения и компилируется в один статический бинарник, что упрощает распространение программы. И вы получаете абстракции высокого уровня, которых нет в других языках, таких как C и C++.

Что ещё может улучшить Rust? Конечно, абстракции ещё более высокого уровня.

С абстракциями более высокого уровня быстро и легко собирается готовый CLI.

Примером такой абстракции является библиотека human panic. В отсутствии такой библиотеки в случае сбоя код CLI, вероятно, выдаст всю обратную трассировку. Но она не очень интересна пользователям. Можно добавить специальную обработку ошибок, но это сложно.

С библиотекой human panic вывод автоматически направится в файл дампа ошибок. Пользователь увидит информативное сообщение, предлагающее сообщить о проблеме и загрузить файл дампа.



Начало разработки CLI-инструментов тоже стало проще. Например, библиотека confy автоматизирует его настройку. Он спрашивает только две вещи:

  • Как называется приложение?
  • Какие параметры конфигурации вы хотите предоставить (которые вы определяете как структуру, которая может быть сериализована и десериализована)?

Всё остальное confy определит самостоятельно.

Что дальше?


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

Инструменты Rust




Когда вы пишете на каком-то языке, вы работаете с его инструментарием: начиная с редактора и продолжая другими инструментами на всех этапах разработки и поддержки.

Это означает, что эффективный язык зависит от эффективных инструментов.

Вот некоторые новые инструменты (и улучшения существующих) в Rust 2018.

Поддержка IDE


Конечно, производительность зависит от быстрого и плавного переноса кода из сознания разработчика на экран компьютера. Здесь решающее значение имеет поддержка IDE. Для этого нужны инструменты, которые могут «объяснить» IDE смысл кода Rust: например, подсказать осмысленные варианты для автодополнения строк.

В Rust 2018 сообщество сосредоточилось на функциях, необходимых IDE. С появлением Rust Language Server и IntelliJ Rust теперь многие IDE полностью поддерживают Rust.

Более быстрая компиляция


Повышение эффективности компилятора означает его ускорение. Это мы и сделали.

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

rustfmt


Эффективность также требует, чтобы мы никогда не спорили о правилах форматирования кода и не исправляли вручную чужие стили.

В этом помогает инструмент rustfmt: он автоматически переформатирует код в соответствии со стилем по умолчанию (по которому сообщество достигло консенсуса). Rustfmt гарантирует, что весь код Rust соответствует одному стилю, подобно формату clang для C++ или Prettier для JavaScript.

Clippy


Иногда приятно иметь рядом опытного консультанта, дающего советы о лучших практиках при написании кода. Это делает Clippy: он проверяет код во время его просмотра и подсказывает стандартные идиомы.

rustfix


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

В этих случаях rustfix автоматизирует процесс. Он одновременно и применяет правила из инструментов вроде Clippy, и обновляет старый код в соответствии с идиомами Rust 2018.

Изменения в сам Rust


Изменения в экосистеме значительно повысили эффективность программирования. Но некоторые проблемы можно решить только изменениями в самом языке.



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

Давайте посмотрим на важные функции, которые добавлены во все версии. Затем посмотрим на небольшой список особенностей Rust 2018.

Новые функции для всех версий


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

Более точная проверка заимствований


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

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


Нельзя заимствовать переменную, потому что она уже заимствована

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

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

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



Пока это доступно только в Rust 2018, но в ближайшее время функцию добавят во все остальные версии. Скоро мы напишем подробнее на эту тему.

Процедурные макросы в стабильном Rust


Макросы в Rust были ещё до Rust 1.0. Но в Rust 2018 сделаны серьёзные улучшения, например, появились процедурные макросы. Они позволяют добавить в Rust собственный синтаксис.

Rust 2018 предлагает два вида процедурных макросов:

Макросы, подобные функциям


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

Они существовали раньше, но с ограниченем. Макрос мог выполнять только оператор match. У него не было доступа, чтобы посмотреть все токены во входящем коде.

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

Макросы, подобные атрибутам


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

Макрос derive делает именно это. Когда вы помещаете его над структурой, компилятор принимает эту структуру (после того, как она проанализирована как список токенов) и обрабатывает её. В частности, добавляет базовую реализацию функций из трейта.

Более эргономичные заимствования в сопоставлениях


Тут незамысловатое изменение.

Раньше, если вы хотели что-то заимствовать и пытались выполнить сопоставление, нужно было добавить какой-то странный синтаксис:



Теперь вместо &Some(ref s) пишем просто Some(s).

Новые функции Rust 2018


Самая малая часть Rust 2018 — это функции, специфичные именно для этой версии. Вот небольшой набор изменений в Rust 2018.

Ключевые слова


В Rust 2018 добавлено несколько ключевых слов:

  • try
  • async/await

Эти функции ещё не полностью реализованы, но ключевые слова добавлены в Rust 1.31. Таким образом, в будущем не придётся вводить новые ключевые слова (что стало бы несовместимым изменением), когда мы реализуем эти функции.

Модульная система


Одна большая боль для новичков Rust — модульная система. И понятно почему. Трудно было понять, почему Rust выбирает тот или иной модуль. Чтобы исправить это, мы внесли некоторые изменения в механизм путей.

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

// top level module
extern crate serde;

// this works fine at the top level
impl serde::Serialize for MyType { ... }

mod foo {
  // but it does *not* work in a sub-module
  impl serde::Serialize for OtherType { ... }
}

Другой пример — префикс ::, который используется и для корня крейта, и для внешнего крейта. Трудно понять, что перед нами.

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

Если вы хотите, чтобы текущий код использовал возможности Rust 2018, скорее всего, потребуется обновить код с учётом новых путей. Но необязательно делать это вручную. Перед добавлением спецификатора версии в Cargo.toml просто запустите cargo fix — и rustfix внесёт необходимые изменения.

Дополнительная информация


Всю информацию о новой версии языка содержит «Руководство по Rust 2018».
Поддержать автора
Поделиться публикацией

Комментарии 23

    0
    Чтобы исправить ситуацию, мы сделали проверку умнее. Теперь она видит, когда переменная фактически завершила использовать значение. После этого она не блокирует использование данных.

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

      +3
      Вызывает подозрительные чувства такая оптимизация. Если раньше можно было просто не задумываться о том, когда переменная, объявленная в начале блока станет доступна, теперь при чтении кода нужно за этим следить.

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


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


      fn main() {
          let mut x = 5;
          let y = &x;
          let mut z = &mut x;
      }

      тут переменная y никак не используется, и её можно спокойно удалить. Но это нам понятно, а старый бч не пропускал такой код. И это тривиальный сценарий, а нетривиальные привели к тому, что пришлось целый entry api например воротить над хэш мапами, потому что не получалось нормально в match использовать мутабельный или readonly борроу.

        0
        За чем следить?

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


        Если смотреть на рафинированый пример то да, очевидно, что после второй строчки y никак не используется.
        Но в реальности будет что-то такое:


        fn main() {
            let mut x = 5;
            // какой-то код 1
            let y = &x;
            // какой-то код 2
            let mut z = &mut x;
            // какой-то код 3
        }

        И визуально может быть не слишком очевидно, где именно после let y = &x; заканчивается использование x.

          +6

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


          По сути поменялось только то, что в некоторых случаях вместо ансейфа мы теперь можем в сейфовом расте сделать то же самое.


          Причем если раьнше такой пример можно было бы сделать просто расставив правильные скобки, то вот этот код без nll написать нельзя:


          fn process_or_default() {
              let mut map = ...;
              let key = ...;
              match map.get_mut(&key) { // -------------+ 'lifetime
                  Some(value) => process(value),     // |
                  None => {                          // |
                      map.insert(key, V::default()); // |
                      //  ^~~~~~ ERROR.              // |
                  }                                  // |
              } // <------------------------------------+
          }
            0
            Для неиспользованных переменных все равно насыплет ворнингов да еще и clippy ругнется до кучи. Так что следить ручками не придется. Если конечно не злоупотреблять всякими сайленсерами.
              0

              Так я же не спорю, что БЧ всё отследит и ворнингов насыпет. Когда что-то пишешь сам — можно и положиться на линтеры.


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


              При этом вещи вроде RAII и другие полезные приспособления нужны в том числе для того, чтобы наоборот не полагаться на внимательность и не терять время.

                +2

                Меня тоже, если честно, немного тревожит этот аспект NLL — что оно более хитрое теперь все. Но 1) не так и просто придумать более-менее реалистичный пример, когда реально из-за этого сильно наступить на грабли 2) очень много людей просто отказывались пользоваться языком с до-NLL проверками, считая язык просто недоработанным (даже на хабре к прошлым статьям десятки таких коментов были).

                  0
                  Мне кажется изменение наоборот позволит упростить код и в некоторых случаях сделать его более понятным без тулинга, избегая ситуаций когда приходится смотреть кому и где я там одолжил свои указатели. Это как в той истории, где в городишко в отель заехал постоялец, сделал предоплату и хозяин отдал долг трактирщику, трактирщик сапожнику, сапожник отдал долг… молочница отдала долг хозяину. Постоялец передумал, забрал предоплату и уехал, а полгорода сократило долги.
                  С NLL это позволяет сокращать такие «долги» автоматически.
          0
          Мы сделали это более явным. Теперь если вы хотите обратиться к корневому крейту, то используете префикс crate::. Это лишь одно из улучшений для понятности.

          Вот с этим я не понял. Был у меня такой код:
          mod foo;
          use foo::bar;
          

          В 2018-mode этот код перестал компилироваться, чтобы заработало, пришлось делать так:
          mod foo;
          use crate::foo::bar;
          

          Я что-то не так делаю или это какое-то неправильное улучшение?
            +1
            Я что-то не так делаю

            Всё так.


            это какое-то неправильное улучшение?

            Улучшение скорее правильное чем нет, но не полностью стабилизированное.


            Если ничего неожиданного не случится, то в 1.32 будет полная версия т.н. "uniform paths" когда пути в импортах (use) относительные и резолвятся точно так же, как и во всех прочих местах.
            (В то время как в Rust 2015 пути в импортах абсолютные и резолвятся относительно корня текущего крейта.)


            В 1.31 "uniform paths" в основном спрятаны под feature, можно использовать только те которые начинаются либо с 1) имени другого крейта, либо 2) crate/self/super.
            foo в примере выше ни то ни другое.

              +1

              В текущем (1.31) поведении на самом деле тоже есть своя логика — если любой импорт начинается либо с имени крейта, либо с ключевого слова, то всегда сразу видно где импортируется своё, а где чужое.
              Есть некоторые сторонники того, чтобы оставить всё как есть и "uniform paths" не включать.

            +2
            Для встроенной разработки необходимо было повысить стабильность существующей функциональности.


            Обожаю такие фразы. Звучит весомо, не значит ничего.

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

            С этим что-то изменилось, или по-прежнему — либо бубен, либо под embedded понимается Raspberry «четыре ядра, четыре гига» Pi?
              0
              blog.japaric.io/embedded-rust-in-2018

              Ну и вообще всё это выглядит не сильно оптимистично.
                0
                Так это годовой давности статья, большая часть проблем уже не актуальна.
                  +2
                  И про это можно прочитать где-то в объёме большем, нежели «наши доблестные разработчики всё исправили»?
                0
                "Для встроенной разработки необходимо было повысить стабильность существующей функциональности."
                Обожаю такие фразы. Звучит весомо, не значит ничего.

                Почему ничего? Есть всякие нестабильные флаги и возможности компилятора, очень полезные для разработки под встройку, но еще не доступные в стабильном канале. Где-то в Embedded WG ресурсах список был — потихоньку дело толкают к стабилизации всего этого хозяйства.


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

                А no_std бинари много места занимают? Вроде не должны бы.

                  +1
                  А no_std бинари много места занимают? Вроде не должны бы.


                  Судя по регулярным вопросам на форумах, «случаи бывают разные», и внезапный рост бинарника в несколько раз от того, что в очередной ночной сборке что-то поломали или поменяли — бывает. А мы говорим о мире, в котором Clang/LLVM не используют, потому что у него до сих пор оптимизация плохая — и он процентов десять GCC проигрывает.

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

                    «внезапный рост бинарника в несколько раз от того, что в очередной ночной сборке что-то поломали или поменяли — бывает»


                    … необходимо было повысить стабильность ....


                    «Звучит весомо, не значит ничего».


                    Кхм, какие-то взаимоисключающие параграфы™.

                      0
                      И как, повысили? И про это можно прочитать где-то в объёме большем, нежели «наши доблестные разработчики всё исправили»?

                      Кхм, какие-то взаимоисключающие параграфы™.


                      Почитайте корпоративные пресс-релизы, они целиком из таких конструкций составлены.
                      0

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


                      … всё это оставляет ощущение глубокой альфы, на которую ещё несколько лет можно даже не смотреть.

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


                      И как, повысили? И про это можно прочитать где-то в объёме большем, нежели «наши доблестные разработчики всё исправили»?

                      Можно, но за подробностями это с уровня таких больших "корпоративных релизов" надо спускаться на уровень конкретных Embedded WG ежемесячников (например, вот) или даже конкретных задач на гитхабе (например вот или вот).

                    –4
                    Пишите на Ada. Она и в 256 байт влезет.
                    +1
                    Я правильно понял, что в стабильный уже завезли NLL?
                      +1

                      Да, с edition = "2018" в Cargo.toml NLL включается.

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

                    Самое читаемое