LINUX.ORG.RU

Rust 1.35

 


1

10

Команда разработчиков Rust рада представить новую версию своего языка: 1.35. Rust - это язык программирования, который позволяет писать надёжные и эффективные программы.

Если у вас уже установлен Rust через rustup,то можно обновиться командой: $ rustup update stable

Главное в обновлении - это реализиция трейтов замыкания Fn, FnOnce, FnMut, для Box<dyn Fn>, Box<dyn FnOnce>, Box<dyn FnMut>, соответственно. Добавление возможности приводить замыкания к указателям на небезопасные функции, вызов макроса dbg!() теперь возможен без аргументов, была проведена стабилизация стандартной библиотеки.

К деталям:

  • В новой версии добавили реализации трейтов Fn, FnOnce, FnMut, для Box<dyn Fn>, Box<dyn FnOnce>, Box<dyn FnMut>, соответственно.
    Теперь такой код будет работать:
    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()
    }
    

  • Теперь замыкания можно приводить к указателям на unsafe fn.
    Сейчас такой код является валидным:
    /// The safety invariants are those of the `unsafe fn` pointer passed.
    unsafe fn call_unsafe_fn_ptr(f: unsafe fn()) {
        f()
    }
    
    fn main() {
        // SAFETY: There are no invariants.
        // The closure is statically prevented from doing unsafe things.
        unsafe {
            call_unsafe_fn_ptr(|| {
                dbg!();
            });
        }
    }
    

  • Добавлена возможность вызова макроса dbg!() без аргументов.
    Если передать этому макросу какое-то выражение то, макрос выведет его результат. Пример:
    fn main() {
        let mut x = 0;
    
        if dbg!(x == 1) {
            x += 1;
        }
    
        dbg!(x);
    }
    
    При запуске такого кода вы увидите:
    [src/main.rs:4] x == 1 = false
    [src/main.rs:8] x = 0
    
    Сейчас вы можете написать вот так:
    fn main() {
        let condition = true;
    
        if condition {
            dbg!();
        }
    }
    
    При выполнении такого кода вы увидите: [src/main.rs:5]
  • Были стабилизированы некоторые части стандартной библиотеки
    • Новые методы для f32 и f64:
      • f32::copysign
      • f64::copysign
      Собственно, функции копируют знак у другого числа. Пример:
      fn main() {
          assert_eq!(3.5_f32.copysign(-0.42), -3.5);
      }
      
    • Добавлены новые методы для Range типов
      • Range::contains
      • RangeFrom::contains
      • RangeTo::contains
      • RangeInclusive::contains
      • RangeToInclusive::contains
      С этими методами можно легко проверить есть ли определенное значение в последовательности:
      fn main() {
          if (0..=10).contains(&5) {
              println!("Five is included in zero to ten.");
          }
      }
      
    • Полный список стабилизированных API вы можете найти тут
  • В этом обновлении, в Clippy (Это программа, которая проверяет ваш код на наличие многих ошибок) добавили новую проверку для drop_bounds. Это проверка срабатывает, когда вы ставите ограниечение: T: Drop - для обобщенных функции:
    fn foo<T: Drop>(x: T) {}
    
    Иметь ограничение T: Drop чаще всего являеться ошибкой, так как сразу исключаются некоторые типы как, например, u8.(Больше об этом можно читать тут)
  • Очень много улучшено и исправлено в Cargo (пакетный менеджер языка), полный список изменений

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

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

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

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

Растбук читается 2 недели. Релизный цикл — 6 недель. Дальше просто почитываешь релизные новости, всё.

К тому же если бы ты реально писал на расте — ты бы и так знал какие фичи ты ждешь и о чем вообще в этих новостях написано.

mersinvald ★★★★ ()

✹ Скобок в йазыке должен быть лишь один вид. А не сцуко 3! ✹ FF однако лучше не стал. Скорее даже наоборот, куда хуже.

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

Разные скобки, как мне кажется, наоборот помогают. Все таки когда я вижу квадратную скобку, то я знаю что это скорее всего массив, фигурные скобки обозначения границ видимости, а сколько значений у круглых скобок. Даже в той же математике используют не только круглые скобки, порой, если много вложенных скобок, то и используют все что только можно.

snake266 ()

fn foo(x: Box<dyn Fn(u8) -> u8>) -> Vec<u8> {

Сложный, перегруженный и неочевидный синтаксис, позволяющий написать сложный и непонятны код. Вот любят же люди отягощать ЯП всякими скобочками.

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

И в каком языке можно подобный смысл выразить с меньшим количеством скобок? Только не говорите, что в питоне, там вообще невозможно выразить понятие типа, не говоря уже о дженериках. Единственно что тут кажется лишним, это Box + dyn, но такова уж философия языка, что всё надо явно описывать.

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

А там ffast-math нинужон?

Да что мне несколько процентов жалко? Вот питон бы я туда не пустил, да и джаву на такое натравливать не хочется

C++ «не справился» бы

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

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

Да что мне несколько процентов жалко?

Ну дык несколько процентов при нескольких запусках уже превращаются в десятки %)

Раст же помогает писать сразу правильно особо не задумываясь.

Ну а чем помогает?

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

Еще вопрос, какая часть кода пострадает от отсутствия быстрой математики. Мой код обычно копирует из массива в массив умножая на что-то. Не факт, что он вообще пострадает.

q0tw4 ★★★ ()
Ответ на: комментарий от Virtuos86
// ==UserScript==
// @name     custom ignore list
// @version  1
// @run-at   document-end
// @grant    none
// @include  https://www.linux.org.ru/*
// ==/UserScript==

(function() {
  var list_of_blocked = [
        "delightfish",
  ];

  document.querySelectorAll('article').forEach((e) => {
    var e_speaker = e.querySelector('a[itemprop=creator]');
    if (!e_speaker) {
      return;
    }
    var speaker = e_speaker.innerText;
    if (!list_of_blocked.includes(speaker)) {
      return;
    }
    var e_msg = e;
    e_msg.style.filter = 'blur(2pt)';
    e_msg.addEventListener("mouseover", function(){
       e_msg.style.filter = '';
    });
    e_msg.addEventListener("mouseout", function(){
       e_msg.style.filter = 'blur(2pt)';
    });
  });
})();
RazrFalcon ★★★★★ ()
Ответ на: комментарий от q0tw4

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

В том же самом свифте.

func foo(x: Array<(Int) -> Int>) -> Array<Int> {
    return [1,2,3].map(x)
}

Не надо говорить что тут другое, там вектор, тип не тот и так далее.
Оба языка черпают вдохновение из каких то новомодных наркотических кумаров и оба языка (ну по крайней мере свифт точно) полное говно, просто потому что мне не нравится на этом писать. Неприятно, некомфортно, неудобно.

Я не понимаю зачем их придумывают. Типизация статическая но есть отдельный тип в котором может быть любой тип, рантайм есть но рантайм проверок нету то есть нульпоинтер отстреливает ноги как в си надо ставить везде проверки. Сборщики мусора опять таки.

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

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

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

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

fn foo(x: impl Fn(u8) -> u8) -> Vec<u8> {
    vec![1, 2, 3, 4].into_iter().map(x).collect()
}
anonymous ()
Ответ на: комментарий от q0tw4

Если я правильно понял код, то на D можно выразить проще

ubyte[] foo(ubyte function(ubyte) x) {
vs
fn foo(x: Box<dyn Fn(u8) -> u8>) -> Vec<u8> {
Даже визуально короче. И это в D ubyte 5 символов, а не 2 как в Rust и function 8 вместо 2 - а так еще короче было бы. Т.е. по факту в D заметно более читабельный (менее замороченный) код и при этом еще и короче. Спасибо за хороший пример.

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

Если я правильно понял код, то на D можно выразить проще

Я не спорю что код на D более лаконичный чем на раст или с++, но все-таки не надо подменять контейнер встроенным массивом (я в курсе что встроенный массив в D вполне заменяет векторы, но это во многом из-за GC), так что правильнее будет:

Array!ubyte foo(ubyte function(ubyte) x) {
anonymous ()
Ответ на: комментарий от anonymous
ubyte[] foo(ubyte function(ubyte) x)

Это указатель на функцию. Соответствующий код в Rust:

fn foo(x: fn(u8) -> u8) -> Vec<u8>

Для использования замыканий нужно использовать delegate

ubyte[] foo(ubyte delegate(ubyte) x)

Но замыкания в D деаллоцируются garbage collector’ом, так что, чтобы получить аналог

fn foo(x: &mut FnMut(u8) -> u8) -> Vec<u8>

нужно ещё будет понаставить @nogc, scope и может быть ещё что-то.

Я недостаточно знаю D, чтобы сказать как сделать аналог

fn foo(x: Box<Fn(u8) -> u8>) -> Vec<u8>
red75prim ★★ ()
Ответ на: комментарий от anonymous

Ну это уже больше детали. Потому что слайс вовсе не означает что память была выделена с помощью сборщика мусора. Это именно слайс на память без какой-либо привязки к аллокатору. Память может быть выделена и каким-нибудь malloc'ом и тем не менее возращаться слайсом. Сборщик просто позволяет не заморачиваться освобождением этого слайса в последствии. Но можно и заморочиться вручную, слайсы этому никак не препятствуют, поэтому моя сигнатура из предыдущего в принципе тоже корректна.

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

Да вдогонку, а как будет выглядеть вызов этой функции в D, я что-то не осилил скормить ей лямбду (давно D не трогал). Для примера в расте все очень просто foo(|x| x + 2);

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

Тут уже я недостаточно хорошо знаю Rust чтобы прокомментировать )) Но в плане контроля за безопасной работой с памятью Rust заморочен больше чем D и возможностей там больше. Вообще идея в основе Rust'а очень здравая, кто бы спорил, но в итоге... Кому-то это хорошо, но я не готов платить такую цену - тяжелый синтаксис, большое время компиляции, высокий порог вхождения и пр. Я виде очень много кода, который написан людьми, которые кучу от стека с трудом отличают. И этот код работает в том числе и в довольно критичных системах. Тот же питон популярен в том числе из-за низкого порога вхождения. Вот если бы Rust позволял по быстрому писать прототип, не заморачиваясь проверками, а потом можно было добавить ключ и заморочится этим - вот это было бы дело имхо. Правда большая часть кода компилировалась только без этого ключика и язык бы уже не мог называться супер безопасным и хайпа тоже было бы уже намного меньше. Зато инструмент был бы тогда действительно толковый.

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

Ну это уже больше детали. Потому что слайс вовсе не означает что память была выделена с помощью сборщика мусора.

Ну слайсы и раст есть и в с++ тоже завозят (в виде range), правда в раст если возвращать слайс будет страшненько так как придется задавать время жизни.

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

Также практически:

foo(a=>cast(ubyte)(a+2));
Единственно cast нужен из-за integer promotion, это наследие от плюсов, если не ошибаюсь, это признано негативным моментом, но решили уже не трогать и оставить как есть. Если тип аргумент имеет размер int и больше, то cast не нужен будет.
foo(a=>a+2); // if a.sizeof >= int.sizeof

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

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

возможно, потому мы и имеем то, что имеем

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

Я тоже первоначально относился к этому строго негативно. Потом жизнь и люди объяснили что это объективная реальность. Так было и будет всегда. Заметно труднее найти и дороже нанять программиста, который разбирается в медицине, чем медработника с навыками программирования. Поэтому заметная часть софта пишется специалистами в своей области, которые программистами не являются. Где-то встречал статью, наверное на Хабре, как автор софта для АЭС, в ответ на замечание, что использование git повышает продуктивность достал тетрадку и сказал, что у него все в тетрадочке записано и git ему не нужен в принципе. И в этой статье еще много много подобного было приведено.

anonymous ()