Привет, Хабр! Представляю вашему вниманию перевод статьи "The Rust Release Team "Announcing Rust 1.34.0".


Команда разработчиков Rust рада сообщить о выпуске новой версии Rust, 1.34.0. Rust — это язык программирования, который даёт возможность каждому создавать надёжное и эффективное программное обеспечение.


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


$ rustup update stable

Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта.


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


Основное улучшение этого выпуска это поддержка альтернативных cargo-реестров. Релиз также включает поддержку ? в документационных тестах, некоторые улучшения в #[attribute(...)] и стабилизацию TryFrom. Читайте далее о ключевых вещах или можете посмотреть подробные примечания к выпуску для дополнительной информации.


Альтернативные cargo реестры


Ещё до версии 1.0 у Rust был публичный реестр, crates.io. Люди публиковали крейты при помощи cargo publish и легко подключали эти крейты в секции [dependencies] в Cargo.toml.


Однако не все хотят публиковать свои крейты на crates.io. Люди, поддерживающие проекты с закрытым исходным кодом, не могли использовать crates.io, и вместо этого им приходилось указывать git или path в зависимостях. Здесь нет ничего такого для небольших проектов, но если в вашей большой организации есть много крейтов с закрытым кодом, вы теряете преимущества поддержки версионирования, которое есть в crates.io.


Начиная с этого выпуска, Cargo может поддерживать альтернативные реестры. Эти реестры сосуществуют с crates.io, так что вы можете писать программы, которые зависят и от crates.io, и от вашего реестра. Однако крейты на crates.io не могут зависеть от внешнего реестра.


Для использования альтернативных реестров, вы должны добавить следующие строки в .cargo/config. Этот файл может быть в вашей домашней директории (~/.cargo/config) или быть в директории пакета.


[registries]
my-registry = { index = "https://my-intranet:8080/git/index" }

Добавить зависимость из альтернативного реестра легко. Когда вы указываете зависимость в Cargo.toml, используйте ключ registry чтобы Cargo знал что вы хотите получать крейт из альтернативного реестра:


[dependencies]
other-crate = { version = "1.0", registry = "my-registry" }

Как автор крейта, если вы хотите публиковать ваш крейт в альтернативном реестре, первым делом вам надо сохранить аутентификационный токен в ~/.cargo/credentials при помощи команды cargo login:


cargo login --registry=my-registry

Далее вы можете использовать флаг --registry для указания реестра, в который будет публиковаться крейт:


cargo publish --registry=my-registry

О том, как вы можете запустить свой собственный реестр, вы можете найти в документации.


? в документационных тестах


В RFC 1937 было предложено добавить поддержку использования оператора ? в fn main(), #[test] функциях и документационных тестах, позволяя им вернуть Option<T> или Result<T, E> где вариант с ошибкой приводит к ненулевому коду завершения в случае fn main() или упавшему тесту в случае тестов.


Поддержка в fn main() и #[test] была реализована достаточно давно. Однако поддержка в документационных тестах была ограничена тестами, в которых явно присутствовал fn main().


В этом выпуске добавлена полная поддержка ? в документационных тестах. Теперь вы можете написать в ваших документационных тестах такое:


/// ```rust
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok::<(), io:Error>(())
/// ```
fn my_func() {}

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


Поддержка произвольного потока токенов в пользовательских атрибутах


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


#[foo(bar)]
#[foo = "bar"]
#[foo = 0]
#[foo(bar = true)]
#[foo(bar, baz(quux, foo = "bar"))]

В отличии от процедурных макросов, эти вспомогательные атрибуты не могли принимать произвольный поток токенов в разделителе, из-за чего вы не могли написать #[range(0..10)] или #[bound(T: MyTrait)]. Крейты процедурных макросов вместо этого использовали строки для синтаксиса, подобного такому, например #[range("0..10")].


С этим выпуском, пользовательские атрибуты #[attr($tokens)] позволяют использовать произвольные токены в $tokens, приводя их в соответствии с макросами. Если вы автор крейта процедурного макроса, пожалуйста проверьте используются ли строки в синтаксисе ваших пользовательских атрибутах и можно ли их заменить на поток токенов.


TryFrom и TryInto


Трейты TryFrom и TryInto были стабилизированы для поддержки ошибок при преобразовании типов.


Например, from_be_bytes и связанные методы целочисленных типов получают массив, но данные часто читаются через слайсы. Ручное преобразование между слайсами и массивами утомительно. С новыми трейтами это возможно сделать в одну строку с .try_into().


let num = u32::from_be_bytes(slice.try_into()?);

Для преобразований, которые не могут завершиться с ошибкой, таких как u8 в u32, добавлен тип Infallible. За счёт этого TryFrom автоматически реализуется для всего, что реализует трейт From. В будущем, мы надеемся сделать Infallible псевдонимом для типа ! (never).


fn before_exec устарела в пользу unsafe fn pre_exec


В Unix-подобных системах функция CommandExt::before_exec позволяла вам запланировать выполнение замыкания до вызова exec.


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


Следовательно, функция before_exec должна быть помечена unsafe. В этом выпуске мы пометили fn before_exec устаревшей в пользу unsafe fn pre_exec. При вызове CommandExt::pre_exec вам необходимо убедиться, что замыкание не нарушает инварианты библиотеки создавая не валидные дубликаты. Если вы предоставляете библиотеку, которая находится в подобной before_exec ситуации, подумайте об устаревании и предоставьте альтернативу с unsafe.


Стабилизация в библиотеках


В 1.34.0 расширен набор стабильных атомарных целочисленных знаковых и беззнаковых типов, начиная с 8 битных (AtomicU8) и заканчивая 64 битными.


Ранее были стабилизированы ненулевые беззнаковые целые числа, такие как NonZeroU8. Благодаря этому Option<NonZeroU8> имеет такой же размер, как и u8. В этом выпуске стабилизированы знаковые версии, например NonZeroI8.


Стабилизированы функции iter::from_fn и iter::successors. Первая позволяет создать итератор из FnMut() -> Option<T>. Чтобы итеративно получать элементы из вектора, вы теперь можете написать from_fn(|| vec.pop()). Тем временем вторая функция создаёт новый итератор, где каждый следующий элемент вычисляется на основе предыдущего.


Дополнительно, были стабилизированы следующие API:



Для подробной информации смотрите подробные примечания к выпуску.

Комментарии (14)


  1. tongohiti
    16.04.2019 22:30
    -2

    Перевести можно было одной фразой: «Этот релиз пустой, расходимся».


    1. ozkriff
      16.04.2019 22:49
      +6

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


      1. idubrov
        17.04.2019 07:42

        Я Any::type_id очень рад… хе-хе. Впрочем, мы по уши на ночной сборке, поэтому более-менее пофиг.


        1. snuk182
          17.04.2019 12:31

          Еееее, в моем проекте одной ночной зависимостью меньше!


    1. oracle_and_delphi
      17.04.2019 05:46

      Хотел спросить «что с объектами в новой версии?»… :(
      (хочу переехать с C++ на Rust, но пугают объекты)


      1. idubrov
        17.04.2019 07:41

        А что с объектами? Чем пугают?


      1. ozkriff
        17.04.2019 08:15

        В этом плане эта версия вообще никаких принципиальных изменений не привносит. Просто почитать что там с ООП в Rust можно, например, в Книге, отдельная глава есть: 17. Object Oriented Programming Features of Rust.


      1. freecoder_xx
        17.04.2019 12:47
        +1

        Вам нужно наследование? Если вам композиция вместо наследования и Deref вместо образования подтипа при наследовании + параметрический полиморфизм не подходят как заменители ООП-наследования, то Rust вам не подойдет. Вероятно, никогда.


        1. Gorthauer87
          18.04.2019 10:34
          +2

          Вообще Deref считается немного антипаттерном.
          https://github.com/rust-unofficial/patterns/blob/master/anti_patterns/deref.md


      1. mayorovp
        17.04.2019 14:26

        А что с ними было не так в старой версии?


      1. defuz
        17.04.2019 15:47

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


        1. idubrov
          17.04.2019 19:20
          +1

          В нашей системе обработка ошибок на основе failure и собственных гм… инструментов мимикрировала в что-то очень похожее на исключения. Цепочки «исключений», даункасты, стектрейсы :D


          1. BlessMaster
            18.04.2019 16:58
            +1

            Похожие требования — похожая инфраструктура.
            Но ошибки — всё-равно не исключения ))


    1. freecoder_xx
      17.04.2019 12:50

      Ну если говорить про чисто языковые улучшения, то в этом релизе — доработка атрибутных макросов… и все :)