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)

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

Код, по типам эквивалентный let y = (), достоен варнинга даже на дефолтном уровне предупреждений

Да? И в каком языке так делается?

Во всех языках, что лично я знаюб эти грабли от eao197 невозможны в принципе

Я не об этом спрашивал. Если захочешь ответить - вопрос выше.

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

Нужно прокачать IQ немножко и всё станет понятно.

Так и про брейнфак можно сказать. Но ты вот почему то питон выбрал, а не перл. Странно, ведь если прокачать IQ на полшишечки, то в перле все понятно. Наверно ты тупой.

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

Раз окей, продолжим.
Поведай, как изъяны языка Си (или любого другого) оправдывают язык Rust?

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

Я даже не буду спрашивать про твою логику. Видимо, ее заменяет раст.

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

Если производительность не важна - можно озаботится чистотой синтаксиса.

Надеюсь сам сможешь развить мысль.

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

означало

Спешите видеть. Я даже боюсь спросить, что у тебя означает слово «логика».
Ты не увиливай, а ответь пожалуйста на вопрос, как изъян одного языка оправдывает другой язык?

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

Второй код что, компилируется без варнингов?

Будет один, потому что результат выражения не используется.

Сам можешь проверить, на что будут предупреждения, а на что нет, здесь: http://play.rust-lang.org

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

Код, по типам эквивалентный let y = (), достоен варнинга даже на дефолтном уровне предупреждений

Да? И в каком языке так делается?

Во всех языках, что лично я знаюб эти грабли от eao197 невозможны в принципе

Я не об этом спрашивал. Если захочешь ответить - вопрос выше.

Зато у меня к тебе вопросов больше не осталось. Либо ты просто не понимаешь, зачем нужны варнинги, либо (скорее всего) делаешь вид.

Ибо твой вопрос про такие же варнинги в других языках имеет смысл лишь в языках, где есть такие же проблемы. В C++ например, такой проблемы (с лишней ;, изменяющей код) нет. Зато там куча своих граблей — и на все их них стараются наложить варнинги, с каждым годом всё плотнее и тщательнее.

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

Можно ли сказать, что раст такой уродский, от того, что создавался, чтобы быть совместимым с древней процессорной архитектурой и устаревшим как гуано мамонта C ABI?

Вон, java c C# сделали себе уютненькие виртуальные машины и резвятся в них как душе угодно

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

Будет один, потому что результат выражения не используется.

Спасибо! Но граблю от eao197 это полностью не закрывает.

fn main() {
    let x = 1;
    let y = {
        x+1;
    };
    println!("x={:?}, y={:?}", x, y);
}
warning: unused arithmetic operation which must be used
x=1, y=()

Однако

fn main() {
    let x = 1;
    let y = {
        1;
    };
    println!("x={:?}, y={:?}", x, y);
}

(без варнингов)

x=1, y=()

Повысить уровень предупреждений как-то может можно?

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

При чём тут архитектура и C ABI? Rust «компилируется» в LLVM IR. А остальное - проблемы llvm (за редким исключением).

Вон, java c C# сделали себе уютненькие виртуальные машины и тормозят в них как душе угодно

fixed

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

Либо ты просто не понимаешь, зачем нужны варнинги, либо (скорее всего) делаешь вид.

Вот так от обсуждения нужности варнинга в одной конкретной ситуации ты перешел к варнингам вообще.

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

Повысить уровень предупреждений как-то может можно?

Да. Tools -> Clippy

warning: this let-binding has unit value. Consider omitting `let y =`
 --> src/main.rs:3:5
  |
3 | /     let y = {
4 | |         1;
5 | |     };
  | |______^
  |
  = note: #[warn(let_unit_value)] on by default
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.209/index.html#let_unit_value

warning: statement with no effect
 --> src/main.rs:4:9
  |
4 |         1;
  |         ^^
  |
  = note: #[warn(no_effect)] on by default
  = help: for further information visit https://rust-lang-nursery.github.io/rust-clippy/v0.0.209/index.html#no_effect

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

Эту «граблю» закрыть нельзя, ибо возвращаться может выражение с побочным эффектом.

// есличо, я противник return

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

Зачем тебе прокачивать IQ? Действительно.
Больше вопросов не имею.

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

Эту «граблю» закрыть нельзя, ибо возвращаться может выражение с побочным эффектом.

Почему нельзя закрыть, когда можно? Ещё на уровне типов видно, что человек написал что-то, эквивалентное let y = ().

А ну вот RazrFalcon и показал, что именно такой варнинг и есть. Вопрос закрыт в принципе.

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

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

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

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

Ещё на уровне типов видно, что человек написал что-то, эквивалентное let y = ()

Частный случай. Замени 1 на f(), и будет неэквивалентно.

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

Прочитай первый из двух варнингов RazrFalcon, это ровно то о чём я говорил

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

Ну когда речь идет про удобные языки, всегда говорят «фуу с программой на этом языке идет „рантайм“». Этот рантайм типа полифилов в js: реализует более лучшую, более современную архитектуру ПК(или ОС?). С более лучшими потоками, с крутым ABI,рефлексией, простым управлением памятью.. От того и языки удобнее

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

А почему ты проигнорировал мой пост?
Rust 1.27 (комментарий)

Давай сначала:
1) Rust 1.27 (комментарий)
1) Есть Х которое не происходит в Rust.

2) Rust 1.27 (комментарий)

Да? И в каком языке так делается?

2) Ты переводишь стрелки на другой язык.

3) Rust 1.27 (комментарий)

А на «char *x = NULL;» он выдает предупреждение?

Объясни же, как знающий «логику», почему действие или отсутствие оного в чём либо другом, отличном от Rust, оправдывает последний?

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

Ты же объективен, а это главное.

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

Я понимаю, что звучит как дичь) Просто хочу донести мысль, что если б такой «рантайм» был общий для всего, от ядра до юзерспейс програм, то язык был бы проще. Ограничения архитектуры накладывают уродливый отпечаток на язык, который создан, чтобы выполняться на этой архитектуре безо всяких рантаймов. Либо уродский аналог C#, зато с современными абстракциями и парадигмами. Либо без парадигм, всё ручками, как в сишке

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

Либо уродский аналог C#, зато с современными абстракциями.

Это в C# более лучшие потоки?

Либо без абстракций, но всё ручками как в сишке

А в Rust нет абстракиций?

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

Архитектуры уже существуют. Остаётся к ним приспосабливаться.

Либо без парадигм, всё ручками, как в сишке

В сишке тоже есть рантайм.

Rust - это попытка показать, что можно современные вкусности сделать без накладных расходов. Есть ещё Zig и Jai, которые ближе к Си.

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

Чего конкретно вам не хватает в Rust?

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

В C# более чистый синтаксис, в т.ч. из-за GC. А рантайм зеленых потоков в ерланге и го. Так-то ничего не мешает все это ***ьмо, в том или ином виде, запихнуть в ядро или в процессор. Вместе с нормальным форматом dll-ок

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

рантайм зеленых потоков в ерланге и го. Так-то ничего не мешает все это ***ьмо, в том или ином виде, запихнуть в ядро или в процессор

Если не знать, как оно внутри работает - конечно, ничто не мешает.

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

PS: Вот вы тут рассказываете про современные парадигмы и абстракции, которые есть в языках с рантаймом, а я такой найти не могу.

Мне нужно:

  • GC
  • Рантайм в бинаре. Java, C# отпадают.
  • Функциональщина. Хотя бы на уровне раста.
  • Поддержка всех современных платформ, а не как в Swift.
  • Исключения. Прощай убогий Go.
  • Стабильный. Nim отпадает.

Ваши предложения?

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

Тормоз.

Забыл самое главное: строгая, статическая типизация.

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

Слишком наркоманский. Не мой уровень.

Многие о Rust'е так же говорят только от того, что он слишком непривычный. Для оперденей ничего лучше Haskell не придумали и вряд-ли ближайшие лет 10 придумают.

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

Для оперденей ничего лучше Haskell не придумали
оперденей

Шта?!

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

Для оперденей ничего лучше Haskell не придумали и вряд-ли ближайшие лет 10 придумают.

Для оперденей (и всех остальных прикладных задач) ленивость Хаскела не нужна. Так что лучше Хаскеля придуман как минимум Ocaml.

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

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

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

PyPy - это ни разу не функциональщина

А раст это сколько раз функциональщина?

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

Тыжпрограмист

Именно поэтому я понимаю сложность задачи и знаю историю вопроса.

неможешь чтоли гринтреды в ядро запихнуть?

Erlang-овые, с инструкциями VM и счетчиком редукций? Не могу.

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