Rust 1.27
Команда разработчиков языка Rust рада представить новую версию Rust 1.27.0. Rust — системный язык программирования, ориентированный на безопасность, скорость и параллельность.
Основные изменения:
- SIMD — наиболее значимое и ожидаемое нововведение: стабильная версия Rust обзавелась базовой поддержкой SIMD.
Для примера использования, рассмотрим следующий сниппет:pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { for ((a, b), c) in a.iter().zip(b).zip(c) { *c = *a + *b; } }
Стабильный Rust уже давно ипользует возможности автовекторизации LLVM, но, к сожалению, компилятор может использовать подобные оптимизации не всегда. В Rust 1.27.0 добавлен модуль std: arch, включающий базовую поддержку использования SIMD инструкций напрямую из кода на Rust. Кроме того, добавлены соответствующие директивы условной компиляции:
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))] fn foo() { #[cfg(target_arch = "x86")] use std::arch::x86::_mm256_add_epi64; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::_mm256_add_epi64; unsafe { _mm256_add_epi64(...); } }
fn foo() { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if is_x86_feature_detected!("avx2") { return unsafe { foo_avx2() }; } } foo_fallback(); }
Примитивы, включенные в стандартную библиотеку обеспечивают минимальную поддержку и весьма низкоуровневы, но их включение позволяет развивать более выкокоуровневые примитывы в библиотеках. К примеру, крейт faster предоставляет удобный интерфейс, основанный на концепции итераторов.
Без SIMD
let lots_of_3s = (&[-123.456f32; 128][..]).iter() .map(|v| { 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 }) .collect::
>(); С SIMD (faster)
let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter() .simd_map(f32s(0.0), |v| { f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0) }) .scalar_collect();
- dyn Trait
Изначальный синтаксис трейт-объектов в Rust — одна из тех вещей, о введении которых мы жалеем: для некоторого трейта Foo, его трейт-объект будет выгдядеть так:
Box
И если Foo является структурой, синтаксис аллокации структуры в «куче» будет выглядеть точно так же.
Когда язык разрабатывался, казалось что сходство здесь уместно, но опыт показал, что это только путает людей.
То же самое справедливо для случая
impl SomeTrait for SomeOtherTrait
, что является корректным синтаксисом, но интуитивно понимается как реализация трейта SomeTrait для всех типов, реализующих SomeOtherTrait, но на самом деле это записывается какimpl
, в то время как первый вариант является реализацией трейта для трейт-объекта.SomeTrait for T where T: SomeOtherTrait Кроме того, появление impl Trait в противовес Trait ввело некую неконсистентность при обучении языку.
Исходя из этого, в Rust 1.27 мы стабилизируем новый синтаксис dyn Trait.
Теперь трейт-объейты выглядят так:// old => new Box
=> Box &Foo => &dyn Foo &mut Foo => &mut dyn Foo То же самое применимо к другим типам указателей:
Arc
теперь объявляется какArc
.Исходя из требований к обратной совместимости, мы не можем удалить старый синтаксис, но мы добавили предупреждение компилятора, призывающее обновить синтаксис для трейт-объектов. Пока что оно выключено по умолчанию.
#[must_use]
для функций
Наконец, аттрибут#[must_use]
получил новые возможности: теперь он применим к функциям.Раньше он использовался только на типах, таких как
Result
, где возвращаемое значение должно быть использовано, но теперь возможно такое применение:#[must_use] fn double(x: i32) -> i32 { 2 * x } fn main() { double(4); // warning: unused return value of `double` which must be used let _ = double(4); // (no warning) }
Также этот аттрибут был добавлен к некоторым функциям в стандартной библиотеке, таким как
Clone::clone
,Iterator::collect
иToOwned::to_owned
, теперь компилятор предупредит в случае, если их результат останется неиспользованным, что поможет заметить и предотвратить случайный вызов затратных операций.
Стабилизация стандартной библиотеки
Новые возможности Cargo
В текущем резизе в Cargo включены два маленьких нововведения:
Во первых, Cargo теперь принимает флаг --target-dir.
Во вторых, Cargo теперь будет пытаться автоматически найти тесты, примеры и исполняемые файлы (прим. бинарные подпроекты в библиотечных крейтах) в проекте, но явная конфигурация, всё же, будет требоваться в некоторых случаях.
Для помощи в конфигурации мы добавили несколько ключевых слов в Cargo.toml.
Обновить Rust можно с помощью команды:
curl https://sh.rustup.rs -sSf | sh # если у вас еще не установлен rustup
rustup update stable
>>> Подробности