LINUX.ORG.RU

Rust 1.27

 


3

10

Команда разработчиков языка 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;
        }
    }
    
    Здесь мы берем два слайса, складываем числа в них и помещаем результат в третий слайс. Самый простой способ, описанный выше — это проход в цикле по каждому слайсу, сложение и сохранение результата. Впрочем, это можно сделать быстрее и в LLVM может автовекторизовать такой код, подставив SIMD инструкции автоматически.

    Стабильный 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(...);
        }
    }
    
    В примере выше флаги cfg позволяют выбрать правильную версию функции в зависимости от целевой архитектуры во время компиляции. Также мы можем это сделать в рантайме:
    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::<Vec<f32>>();
    

    С 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>

    И если Foo является структурой, синтаксис аллокации структуры в «куче» будет выглядеть точно так же.

    Когда язык разрабатывался, казалось что сходство здесь уместно, но опыт показал, что это только путает людей.

    То же самое справедливо для случая impl SomeTrait for SomeOtherTrait, что является корректным синтаксисом, но интуитивно понимается как реализация трейта SomeTrait для всех типов, реализующих SomeOtherTrait, но на самом деле это записывается как impl<T> SomeTrait for T where T: SomeOtherTrait, в то время как первый вариант является реализацией трейта для трейт-объекта.

    Кроме того, появление impl Trait в противовес Trait ввело некую неконсистентность при обучении языку.

    Исходя из этого, в Rust 1.27 мы стабилизируем новый синтаксис dyn Trait.
    Теперь трейт-объейты выглядят так:

    // old => new
    Box<Foo> => Box<dyn Foo>
    &Foo => &dyn Foo
    &mut Foo => &mut dyn Foo
    

    То же самое применимо к другим типам указателей:
    Arc<Foo> теперь объявляется как Arc<dyn Foo>.

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

  • #[must_use] для функций
    Наконец, атрибут #[must_use] получил новые возможности: теперь он применим к функциям.

    Раньше он использовался только на типах, таких как Result<T, E>, где возвращаемое значение должно быть использовано, но теперь возможно такое применение:

    #[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

>>> Подробности

★★★★★

Проверено: tailgunner ()
Последнее исправление: cetjs2 (всего исправлений: 5)

Ответ на: комментарий от StillSteal

Долгих лет тебе и быстрого развития

Одно с другим нифига не совместимо

Deleted
()
Ответ на: комментарий от anonymous

Про макак правда, но это же не минус. Высокоуровневые языки для того и существуют, чтобы облегчить написание и прочтение кода, а не для того чтобы пердолиться с тем, сколько ты скобочек поставил (привет лиспу), и по 10 раз прописывать тип для одних и тех же данных. Тут с го почти всё в порядке, исключая локальное виденье асинхронности и отсутствие нормального контроля над потоками, изначально это только раздражает. В плане выразительности он так себе, да. Зато он быстрый и без граблей.

А топорный он потому, что выглядит как кастрированный C, или что? На счёт поделки из прошлого не согласен, вышеназванная дрянь с потоками и асинхронность — это довольно прогрессивно.

WitcherGeralt ★★
()
Ответ на: комментарий от Nexmean

благодаря правильным абстракциям

Успокойся уже с абстракциями и читабельностью. Лучший язык - тот, который лучше знаешь(+-)

Deleted
()
Ответ на: комментарий от anonymous

корпоративные макаки
обезьяна

Я так понимаю, вот это - тоже твой коммент. Go штоле ниасилил?

Deleted
()
Ответ на: комментарий от anonymous

Не скажи. Я пару вакансий уже видел

Deleted
()
Ответ на: комментарий от WitcherGeralt

Я слабо себе представляю что делают первые два куска, к вопросу о читабельности ага, но последний в расте будет лаконичнее.

RazrFalcon ★★★★★
()
Ответ на: комментарий от WitcherGeralt

А теперь сравни это с растом и жестью, которую можно нахерачить на плюсах.

Так код на Go хорошо читается сам по себе, или хорошо читается в сравнении с воображаемой жестью на плюсах и Расте?

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

к вопросу о читабельности

Успокойтесь уже, сколько можно-то )

Deleted
()
for ((a, b), c) in a.iter().zip(b).zip(c) {
        *c = *a + *b;
    }

Я чего-то не понял или это то, что в C++ с valarray делается как просто c = a + b, без всяких циклов, но со слайсами и SIMD?

seiken ★★★★★
()
Ответ на: комментарий от anonymous

Ну давай, расскажи, что умеет Qt такого, чего не сделать на GTK.

Вопрос из разряда «чем Ниссан лучше кузова от Тойоты».

GTK - это аналог модулей QtGui и QtWidgets, если корректно сравнивать.

// Против GTK, в общем-то, ничего не имею.

hobbit ★★★★★
()

По сабжу — чем больше новостей про этот язык я читаю, тем сильнее ощущение, что у него очень перегруженный синтаксис, и велика вероятность повторения судьбы ПЛ/1. Хотя попытка интересная, да.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от hobbit

очень перегруженный синтаксис

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

anonymous
()
Ответ на: комментарий от O02eg

Надо признать, что компилятор будет орать ворнингами очень громко о таком коде.

provaton ★★★★★
()
Ответ на: комментарий от hobbit

что у него очень перегруженный синтаксис,

А опыт собственно работы с языком у вас был? Или только примеры из новостей читали?

provaton ★★★★★
()
Ответ на: комментарий от RazrFalcon

Первое — map с ключом стрингом и значеним из data, которое, видимо, стракт который задали в качестве типа, второе — просто список (если опустить упоротую терминологию Go) страктов. Это понятно после беглого прокликивания «A tour of Go», который я поленился докликать.

А после просмотра аналогичного (правда более короткого) «Rust by Example», ты всё равно ничерта не поймёшь даже в относительно тривиальном коде на Rust (по крайней мере я ннп и долго пускал слюну, глядя на нечто, как позже оказалось, примитивное. Чёртовы ретурны, которых нет). Более пристальное изучение языка и чтение действительно сложного кода, наверняка, иногда вызывает необратимые повреждения мозга.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

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

А вы хоть что-то отдалённо напоминающее функциональный язык программирования когда-нибудь пытались освоить?

Nexmean
()
Ответ на: комментарий от WitcherGeralt

К естественным языкам это не относится случайно? А то русский - вон какой сложный, склонения, спряжения, согласования падежей, и т.д. и т.п. У меня возникают подозрения.

red75prim ★★★
()
Ответ на: комментарий от Deleted

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

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

хорошо, когда нет всяких чёрточек, херотучи разных скобочек, которые в разных местах означают кардинально ращные вещи

Приведи пример, где в Rust разные «черточки» и «скобочки» в разных местах означают кардинально разные вещи.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

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

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

когда не происходит ничего неявного и неожиданного

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

Deleted
()
Ответ на: комментарий от WitcherGeralt

Так код на Go хорошо читается сам по себе, или хорошо читается в сравнении с воображаемой жестью на плюсах и Расте?

Сам по себе неплохо читается

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

Ты отрицаешь, что плюсы слишком многое позволяют?

Я отрицаю, что примеры из Си++ релевантны в разговоре о Rust.

дичь в плюсах, равно как в джаваскрипте, — это уже давно отдельный жанр.

Выше приведена дичь в Go.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Тогда я не понял, кто кого и с какой стороны догоняет.

----------------------------> сложность
1) Rust     PL/I     C++
2) PL/I     C++     Rust
Первый не подходит под «тем более», а второй - под «догнать по сложности»(???)

Deleted
()
Ответ на: комментарий от WitcherGeralt

map с ключом стрингом и значеним из data
второе — просто список страктов.

Насколько я понимаю, не просто значений, а указателей на них.

А после просмотра аналогичного (правда более короткого) «Rust by Example», ты всё равно ничерта не поймёшь даже в относительно тривиальном коде на Rust

4.2

1. Это не официальная дока, насколько я знаю.

2. У меня таких проблемы не было. При условии что я из C++ вышел. Так что не нужно говорить за всех.

Это понятно после беглого прокликивания «A tour of Go», который я поленился докликать.

А я не поленился. Но всё равно впал в ступор.

Тут скорее проблема в том, что в Rust не нужно указывать типы, поэтому вместо ужаса вроде map[string]*data достаточно HashMap::new().

Чёртовы ретурны, которых нет

Одна из моих любимейших фич.

RazrFalcon ★★★★★
()
Ответ на: комментарий от WitcherGeralt

Вы сейчас описали Rust. Вы уверены что мы с вами про один язык говорим? Ибо ваши хотелки - это явно не Go.

RazrFalcon ★★★★★
()
Ответ на: комментарий от Nexmean

Макросами не прокостылять генераторы для обработчиков прерываний. Короче, то что оно есть в макросах - хорошо, но родное - еще лучше. Это очень востребованная фича для современного программирования.

Vit ★★★★★
()
Ответ на: комментарий от tailgunner

Догоняешь?

Нет( «тем более» подразумевает большее усилие/срок, но ситуация обратная же. Можно, конечно, на читабельность русского списать, но это так себе вариант

Deleted
()
Ответ на: комментарий от Deleted

Это определяется знанием тонкостей языка

Не всегда «тонкости» это просто тонкости. Зачастую это косяки компилятора/интерпретатора, которые десятилетиями не правят ради совместимости. Я выше уже приводил пример джавасткрипта, где это особенно очевидно.

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

Чёртовы ретурны, которых нет

Каждое выражение вырабатывает значение. Значением функции является последнее выражение. Ничего странного для тех, кто знает об expression-oriented языках.

tailgunner ★★★★★
()
Ответ на: комментарий от WitcherGeralt

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

Deleted
()
Ответ на: комментарий от tailgunner

Это не странность, это неочевидности в коде, порождаемые синтаксисом. Ретурн за километр видно, а тут нужно ещё распарсить чего происходит. Кто и почему решил что ретурны не нужны, какой смысл от них избавляться?

WitcherGeralt ★★
()
Ответ на: комментарий от Vit

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

Nexmean
()
Ответ на: комментарий от WitcherGeralt

Это не странность, это неочевидности в коде

В этом нет ничего неочевидного. Совсем.

порождаемые синтаксисом

А... видишь ли, синтаксис здеь не причем. Это семантика.

Кто и почему решил что ретурны не нужны, какой смысл от них избавляться?

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

tailgunner ★★★★★
()
Ответ на: комментарий от hobbit

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

Подправил тебя

anonymous
()
Ответ на: комментарий от WitcherGeralt

Ретурн за километр видно, а тут нужно ещё распарсить чего происходит

Ретурн вам за километр видно, а где кончается функция вам сложно распарсить? Вы это серьёзно?

Nexmean
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.