- PVSM.RU - https://www.pvsm.ru -

Выпуск Rust 1.35.0

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

Введение

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

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

$ rustup update stable

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

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

Главными новшествами этого релиза можно назвать реализации трейтов FnOnce, FnMut и Fn на структурах Box<dyn FnOnce>, Box<dyn FnMut> и Box<dyn Fn> соответственно.

А также встраиваемые функции (closures) могут быть сконвертированы в небезопасные указатели на функции. Макрос dbg!, введённый в Rust 1.32.0 [5], теперь может быть вызван без указания аргументов.

Более того, данный релиз внёс множество стабилизаций стандартной библиотеки. Ниже представлены наиболее существенные, но доступен и детальный разбор [4] оных.

Fn* трейты реализованы на Box<dyn Fn*>

В Rust 1.35.0, трейты FnOnce, FnMut и Fn реализованы [6] на Box<dyn FnOnce>, Box<dyn FnMut> и Box<dyn Fn> соответственно.

В прошлом, если Вы желали вызвать функцию, инкапсулированную в Box, Вам необходимо было воспользоваться FnBox [7], так как объекты Box<dyn FnOnce> и подобные не реализовывали соответствующие трейты Fn*. Это также мешало передачи инкапсулированных в Box функций коду, ожидавшему реализатора трейта Fn (предлагалось создавать временные встраиваемые функции).

Это было вызвано неспобностью компилятора обнаружать подобные реализации. Этот недостаток был устранён с введением unsized_locals [8].

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

fn foo(x: Box<dyn Fn(u8) -> u8>) -> Vec<u8> {
    vec![1, 2, 3, 4].into_iter().map(x).collect()
}

Объекты Box<dyn FnOnce> могут быть вызваны без лишней возни:

fn foo(x: Box<dyn FnOnce()>) {
    x()
}

Конвертация в небезопасные указатели

Со времен Rust 1.19.0 [9] стало возможным конвертирование встраиваемых функций, не захватывавших среду в указатели на функции. Например, вы могли написать:

fn twice(x: u8, f: fn(u8) -> u8) -> u8 {
    f(f(x))
}

fn main() {
    assert_eq!(42, twice(0, |x| x + 21));
}

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

/// Безопасные инварианты, переданные в `unsafe fn`.
unsafe fn call_unsafe_fn_ptr(f: unsafe fn()) {
    f()
}

fn main() {
    // БЕЗОПАСНОСТЬ: тут нет никаких инвариантов
    // Данная функция статически предотвращена от небезопасных
    // операций
    unsafe {
        call_unsafe_fn_ptr(|| {
            dbg!();
        });
    }
}

Вызов dbg!() без аргументов

Вследствие обилия вызовов println! в качестве колхозных дебаггеров, в Rust 1.32.0 [5] был представлен макрос dbg! [10]. Напомним, что данный макрос позволяет быстро запечатлить результат некого выражения с контекстом:

fn main() {
    let mut x = 0;

    if dbg!(x == 1) {
        x += 1;
    }

    dbg!(x);
}

Приведённые выше строки кода напечатают в терминал результат выражения x == 1 и x соответственно:

[src/main.rs:4] x == 1 = false
[src/main.rs:8] x = 0

Как было сказано в предыдущей секции, где может быть вызвана функция высшего порядка call_unsafe_fn_ptr, dbg!() также подлежит вызову без указания аргументов. Это может быть крайне полезно для обнаружения выбранных программных веток:

fn main() {
    let condition = true;

    if condition {
        dbg!(); // [src/main.rs:5]
    }
}

Стабилизации стандартной библиотеки

В Rust 1.35.0, множество компонентов стандартной библиотеки были стабилизированы. В дополнении к этому, были внесены некоторые реализации, о которых Вы можете прочесть тут [4].

Копирование знака числа с плавающей точкой в другое число

С данным релизом, новые методы copysign были добавлены в примитивы с плавающей точкой (конкретнее, f32 и f64):

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

fn main() {
    assert_eq!(3.5_f32.copysign(-0.42), -3.5);
}

Проверка того, содержит ли Range определённое значение

Rust 1.35.0 приобрёл парочку новых методов на структурах Range*:

С помощью данных методов, Вы можете с лёгкостью проверить, находится ли определённое значение в диапазоне. Например, Вы можете написать:

fn main() {
    if (0..=10).contains(&5) {
        println!("5 находится в диапазоне [0; 10].");
    }
}

Перевести (map) и разбить (split) заимствованный RefCell

С приходом Rust 1.35.0, Вы можете перевести и разбить заимствованное значение RefCell на множество заимствованных значений на разные компоненты заимствованных данных:

Переставить значение RefCell через встраиваемую функцию

Этот релиз представляет удобный метод replace_with, объявленный на структуре RefCell:

Хешировать указатель или ссылку по адресу

Данный релиз представляет функцию ptr::hash [21], принимающую сырой указатель для хеширования. Использование ptr::hash способно предотвратить хеширование указываемого или ссылаемого значения вместо самого адреса.

Копирование контента Option<&T>

С началом Rust 1.0.0, методы Option::cloned на Option<&T> и Option<&mut T> позволяли клонировать содержание в случае его присутствия (Some(_)). Однако клонирование иногда может быть дорогостоящей операцией, а методы opt.cloned() не описывали никаких подсказок.

Этот релиз внёс:

Функциональность opt.copied() такая же, как и opt.cloned(). Однако описанный выше метод запрашивает условия T: Copy, невыполнение которого вызвет ошибку компиляции.

Изменения в Clippy

Clippy, инструмент, отлавливающий часто встречаемые несовершенности для повышения качества кода, обзавёлся drop_bounds [23]. Оно срабатывает в тех случаях, когда обобщённая функция запрашивает выполнения условия T: Drop:

fn foo<T: Drop>(x: T) {}

Это часто является ошибкой, так как примитивы не реализуют Drop. Более того, T: Drop не покрывает типы, подобные String, не имеющие наглядного поведения деструктора, а скорее результат встраиваемых типов (как Vec<u8>).

В дополнении к drop_bounds [23], данный релиз разделяет [24] redundant_closure в redundant_closure и redundant_closure_for_method_calls.

Прочесть детальный релиз Clippy можно тут [25].

Изменения в Cargo

Детальное описание изменений Cargo доступно здесь [26].

Участники 1.35.0

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

Автор: Мырзамади Темирхан

Источник [28]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/open-source/318690

Ссылки в тексте:

[1] публикации: https://blog.rust-lang.org/2019/05/23/Rust-1.35.0.html

[2] Rust: https://www.rust-lang.org/

[3] получить его: https://www.rust-lang.org/install.html

[4] Детальный обзор: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1350-2019-05-23

[5] Rust 1.32.0: https://blog.rust-lang.org/2019/01/17/Rust-1.32.0.html#the-dbg-macro

[6] реализованы: https://github.com/rust-lang/rust/pull/55431

[7] FnBox: https://doc.rust-lang.org/1.34.0/std/boxed/trait.FnBox.html

[8] unsized_locals: https://doc.rust-lang.org/nightly/unstable-book/language-features/unsized-locals.html

[9] Rust 1.19.0: https://blog.rust-lang.org/2017/07/20/Rust-1.19.html

[10] dbg!: https://doc.rust-lang.org/std/macro.dbg.html

[11] f32::copysign: https://doc.rust-lang.org/std/primitive.f32.html#method.copysign

[12] f64::copysign: https://doc.rust-lang.org/std/primitive.f64.html#method.copysign

[13] Range::contains: https://doc.rust-lang.org/std/ops/struct.Range.html#method.contains

[14] RangeFrom::contains: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html#method.contains

[15] RangeTo::contains: https://doc.rust-lang.org/std/ops/struct.RangeTo.html#method.contains

[16] RangeInclusive::contains: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html#method.contains

[17] RangeToInclusive::contains: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html#method.contains

[18] Ref::map_split: https://doc.rust-lang.org/std/cell/struct.Ref.html#method.map_split

[19] RefMut::map_split: https://doc.rust-lang.org/std/cell/struct.RefMut.html#method.map_split

[20] RefCell::replace_with: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.replace_with

[21] ptr::hash: https://doc.rust-lang.org/std/ptr/fn.hash.html

[22] Option::copied: https://doc.rust-lang.org/std/option/enum.Option.html#method.copied

[23] drop_bounds: https://rust-lang.github.io/rust-clippy/master/index.html#drop_bounds

[24] разделяет: https://github.com/rust-lang/rust-clippy/pull/4101

[25] тут: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-135-beta

[26] здесь: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-135-2019-05-23

[27] спасибо: https://thanks.rust-lang.org/rust/1.35.0/

[28] Источник: https://habr.com/ru/post/453338/?utm_source=habrahabr&utm_medium=rss&utm_campaign=453338