Выпуск Rust 1.36.0: Трейт Future, стабилизация alloc и MaybeUninit<T>

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


    Введение


    Команда по разработке языка программирования Rust рада анонсировать новую версию, 1.36.0. Rust — это язык программирования, позволяющий каждому разрабатывать надёжное и быстрое ПО.


    Если предыдущую версию Rust вы установили средствами rustup, получение текущей версии не составит особого труда:


    $ rustup update stable

    Если у вас всё ещё нет rustup, вы можете получить его с соответствующей страницы на нашем сайте. Детальный обзор данного релиза доступен на GitHub.


    Что вошло в стабильную версию?


    Данный релиз привнёс множество изменений, включая стабилизацию долгожданного трейта Future, крейта alloc, структуры MaybeUninit<T>, NLL для Rust 2015, новую реализацию HashMap<K, V> и поддержку флага --offline в Cargo.


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


    Стабилизация трейта Future


    Rust 1.36.0 стабилизировал долгожданный трейт Future!


    Мы надеемся, что это нововведение позволит популярным крейтам, библиотекам и в целом всей экосистеме подготовиться к синтаксису async/.await, стабилизация которого планируется на недалёкое будущее.


    Стабилизация крейта alloc


    До версии 1.36.0 стандартная библиотека состояла из крейтов std, core и proc_macro. Крейт core имел базовую функциональность (такую как Iterator и Copy) и мог быть использован в средах с #![no_std], так как он не налагал никаких требований. Между тем, крейт std поставлял такие типы, как Box<T>, а также функциональность операционной системы (глобальный аллокатор).


    Начиная с Rust 1.36.0, компоненты крейта std, зависимые от глобального аллокатора, например, Vec<T>, сейчас доступны в крейте alloc. Крейт std, тем временем, реэкспортирует данные компоненты.


    В то время как программы с #![no_std], использующие крейт alloc, всё ещё требуют канала nightly, библиотеки с #![no_std] могут использовать крейт alloc в стабильном Rust.


    Также отметим, что все "обычные" программы (без #![no_std]) в своих зависимостях способны содержать описанные выше библиотеки с #![no_std]. Мы надеемся, что это будет содействовать разработке экосистемы, совместимой с #![no_std].


    Если вы являетесь разработчиком библиотеки, требующей примитивы аллокации для функционирования, советуем пометить свою библиотеку как совместимой с #![no_std], используя следующий синтаксис в начале файла lib.rs:


    #![no_std]
    
    extern crate alloc;
    
    use alloc::vec::Vec;

    MaybeUninit место mem::uninitialized


    В предыдущих релизах Rust функция mem::uninitialized разрешала вам отменять проверки инициализации, так как полагала, что вы УЖЕ выполнили инициализацию типа T, не делая ничего. Одно из использований данной функции была "ленивая" аллокация массивов.


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


    Например, вызов mem::uninitialized::<bool>() немедленно вызовет неопределённое поведение, так как с точки зрения Rust, неинициализированные биты являются либо нулём (false), либо единицей (true), и лишь два вышеописанных паттерна подходят для типа bool.


    Чтобы разрешить данную ситуацию, в Rust 1.36.0 был стабилизирован тип MaybeUninit<T>. Компилятор Rust теперь не предполагает, что MaybeUninit<T> является инициализированным типом T. Тем самым, вы можете выполнять постепенную инициализацию более безопасно и наконец-то использовать .assume_init() когда вы уверены, что maybe_t: MaybeUninit<T> содержит инициализированный тип T.


    Так как MaybeUninit<T> является более безопасной альтернативой, начиная с Rust 1.38, функция mem::uninitialized будет помечена устаревшей.


    Чтобы узнать больше о неинициализированной памяти, mem::uninitialized и MaybeUninit<T>, почитайте статью Алексиса Бессесснера. Стандартная библиотека также содержит достаточную документацию о MaybeUninit<T>.


    NLL для Rust 2015


    В объявлении о Rust 1.31.0 мы рассказали вам о NLL (нелексические лайфтаймы), нововведении в язык, делающим контроллера ссылок (borrow checker) умнее и дружелюбнее. Например, теперь вы можете написать так:


    fn main() {
        let mut x = 5;
        let y = &x;
        let z = &mut x; // Не было разрешено до 1.31.0
    }

    В 1.31.0 NLL был стабилизирован только для Rust 2018, и предполагалось, что мы перенесём его в Rust 2015 в будущем. Это было сделано в Rust 1.36.0, NLL стал доступным для Rust 2015.


    С NLL, поддерживаемым в обеих версиях, мы приближаемся к удалению старого контроллера ссылок. Однако старый контроллер ссылок, к сожалению, принял некорректный код, который он НЕ должен был принять.


    И, как результат, NLL сейчас находится на стадии "миграции", в которой мы будем выдавать предупреждения вместо ошибок в том случае, если контроллер ссылок NLL не одобрит код, который бы одобрил старый контроллер ссылок на основе AST. Советуем взглянуть на список пострадавших публичных крейтов.


    Чтобы узнать больше о NLL, MIR, об исправлении соответствующих проблем целостности, а также о том, что можно сделать с появившимися предупреждениями компилятора, прочтите статью Феликса Клока.


    Новая реализация HashMap


    В Rust 1.36.0 предыдущая реализация HashMap<K, V> была заменена реализацией из крейта hashbrown, основанной на дизайне SwissTable. Интерфейс остался прежним, но нынешняя реализация в среднем быстрее и потребляет меньше памяти. Однако заметьте, что стандартная реализация всё ещё использует алгоритм SipHash 1-3.


    Поддержка --offline в Cargo


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


    Rust 1.36.0 стабилизировал новый флаг --offline. Данный флаг отменяет алгоритм разрешения зависимостей, вместо этого используя локальные закешированные зависимости.


    Если запрашиваемые крейты недоступны без сети, которая была отключена, то Cargo завершит работу с ошибкой. Чтобы предварительно заполнить локальный кеш до ухода из сети, используйте команду cargo fetch, загружающую все необходимые зависимости для конкретного проекта.


    Чтобы узнать больше о --offline и cargo fetch, прочтите статью Ника Камерона. Другие изменения в Cargo детально описаны тут.


    Изменения в библиотеке



    Другие изменения


    Подробные описания изменений в версии 1.36.0 доступны для Rust, стандартной библиотеки, Cargo и Clippy.


    Участники 1.36.0


    Множество людей собрались вместе, чтобы создать Rust 1.36.0. Мы не смогли бы сделать это без всех вас, спасибо!


    От переводчика


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


    Поддержать автора
    Поделиться публикацией

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

      +2
      предыдущая реализация HashMap<K, V> была заменена реализацией из крейта hashbrown

      стандартная реализация всё ещё использует алгоритм SipHash 1-3.

      Можно расшифровать, что всё таки заменили и что изменилось?
      Если я сделаю use std::collections::HashMap у меня будет новая реализация или старая?
        +12

        Будет новая реализация хеш-таблицы, но со старой хеш-функцией. hashbrown по умолчанию использует FxHash, который значительно быстрее, но менее безопасен в плане защиты от DoS атак.

        +4
        С каждым разом все лучше и лучше.
          +2
          Документацию по новым фьючам похоже держат в тайне, по примерам приходится осваивать :)
        +3

        У вас ссылка не на плохой код, а на википедию, на статью Soundness.

          +1

          В оригинале ссылка также ведёт на Википедию.

          +2

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

            +1

            "Поиск того, что нужно" = мало библиотек?

              +3

              Ну вот не надо, про "такого же уровня". Я сейчас вожусь с gtk-rs, и я реально вынужден расковыривать существующие приложения, чтобы понять как с ним работать. Сравните с документацией к GTK на С и питоне.


              А про поиск я имел в виду возможность отфильтровать "залил на crates, счастлив" с реально работающей библиотекой. Я потратил несколько дней, пытаясь найти библиотеку, которая мне "скопирует картинку в clipboard". (https://medium.com/journey-to-rust/working-with-clipboard-b4564b906d46). На выходе — не мало ни много — gtk, потому что всё остальное — страх и ужас.

                +6

                Всё-таки это больше проблема gtk-rs, а не экосистемы в целом (ну если не брать очевидную молодость экосистемы). Тут ещё и некоторая неидиоматичность накладывается. В биндингах к gstreamer тоже без бутылки курения сишной документации не разберёшься. Обычно у проектов на чистом Расте с документацией всё сильно лучше.

                  +1

                  Не в случае gtk-rs. Там все, что за пределами хеллоуворлда, реализуемо далеко не предсказуемым путем. Разумеется, ни черта не документировано.

                  +3

                  rust для gui пока полностью не готов (согласно версии самих разрабов). gtk-rs это же какие-то биндинги в полу-автоматическом режиме сгенерированные. Т.е. на си ожидаемо будет гораздо больше туториалов. Кстати extern crate не обязательно писать в 2018 версии.

                    +1
                    По-моему Гуи на расте вообще не мейнстрим, авторам языка это направление пофиг, все на энтузиастах, кто еще не успел на Веб перескочить :)
                      0

                      Для гуя, как ни крути, нужно наследование is-a. В Rust с этим печально.

                        –1
                        Наследование трейтов есть, у трейтов есть реализации по умолчанию, для доступа к данным у базового трейта можно наваять геттеров/сеттеров, то есть практически ООП, но ребята так не советуют делать из-за борров-чекера, типа именно по причине ограничения владения ООП нерекомендуема, и весь полиморфизм советуют делать на женериках. Я не знаю что тут сказать, для ГУИ можно использовать счетчики ссылок и не заморачиваться с владением, только нафига вообще все это когда есть нормальные PWA.
                          +1

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

                            0
                            Не понимаю, о каком состоянии речь, вот два трейта, один наследует от другого, внутри переменная a, доступна из реализации обоих трейтов, согласен, костыль, но работает же.
                            play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=3f46ae38d7d45b8acd7d11deaff0b072
                              +1
                              1. Шарить состояние = костыли для его доступа.
                              2. Наследовать поведение = копипаста методов наследуемого типа. В двумя-тремя-пятью методами прокатит, но в случае UI методов десятки.
                +2
                По крайней мере библиотеки в одном месте, единый репозитарий это сильно lib.rs
                  +3

                  Да, разумеется, я оттуда начинал. Если честно, вещи, которой не хватает, это некоторого независимого описания — что крейт делает, а что нет.


                  Я не говорю, что "всё плохо", я говорю, что по сравнению с уютным "много книжек по расту" с кучей гайдов и т.д., ситуация с библиотеками (их описанием и документацией) много хуже. Оно ощущается как обрыв — было хорошо и просто отлично, и вдруг, ты один на один с библиотекой у которой из всей документации два с половиной примера, не покрывающих основного функционала библиотеки.

                    +2
                    Для этого нужно майнтейнерам вручную модерировать выпуск каждой версии крейта, и заворачивать если описание меньше 3-х страниц или примеры не работают. И еще деньги брать за аудит, как в магазине эпла :)
                      +1

                      Идея мейнтейна на самом деле не требует централизованной authority. Достаточно достаточно большого коллектива (как в debian, например). Теоретически, группа опытных пользователей может проводить тривиальное review до включения кода в публичную выдачу crates. Хорошо описанная и простая в реализации полиси поможет.


                      Второй вариант (конечно, требующий особых добровольцев) — курируемый список с достаточным количеством примеров и описанием.

                  0

                  Благодаря docs.rs документация худо-бедно, но есть. Что хуже, так это поддерживаемость библиотек — подход "написал, выложил, забыл" все еще цветет и пахнет.

                  +2

                  Все еще непонятно, как использовать MaybeUninit с массивами. Зря они переименовали into_inner в assume_init, первый вариант имхо подходил больше.


                  P.S. Перевод местами цепляет глаз: например, порядок слов в В Rust 1.36.0 новый флаг --offline был стабилизирован. чисто англоязычный.

                  +3
                  отличная новость!

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

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