LINUX.ORG.RU

Релиз языка программирования Rust 1.39

 ,


1

8

Rust — мультипарадигмальный компилируемый язык программирования общего назначения, спонсируемый Mozilla, сочетающий парадигмы функционального и процедурного программирования с объектной системой, основанной на типажах, и с управлением памятью через понятие «владения».

Что нового в версии 1.39:

  • стабилизирован новый синтаксис асинхронного программирования, основанный на функции «async», блоке async move { … } и операторе «.await»;
  • разрешено указание атрибутов при определении параметров функций, замыканий и указателей на функции. Поддерживаются атрибуты условной компиляции (cfg, cfg_attr), управляющие диагностикой через lint и вспомогательные атрибуты вызова макросов;
  • стабилизирован «#feature(bind_by_move_pattern_guards)», который позволяет использовать переменные с типом привязки «by-move» в шаблонах;
  • предупреждения о проблемах при проверке заимствования переменных c использованием NLL переведены в разряд фатальных ошибок;
  • в пакетный менеджер cargo добавлена возможность использования расширения «.toml» для файлов конфигурации.

С полным списком изменений можно ознакомиться на сайте разработчика.

>>> Источник

★★★★★

Проверено: cetjs2 ()
Последнее исправление: cetjs2 (всего исправлений: 4)
Ответ на: комментарий от example_cat

Microsoft начала переписывать ядро на rust для эксперимента.

Не на 100% довольны ЯП, но утверждают что подходит.

Они тоже «ни ухом ни рылом» ?

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

Лабы на них не пишут, слишком сложно. На OCaml пишут …

Ну это же просто неправда! Ocaml не сложнее питона или go какого-нибудь.

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

И?
Между 'int* t = NULL;' и 'print_int(*t);' может оказаться 100500 строк кода, либо ты вообще получаешь указатель из другой функции.
И наличие ссылок никак не спасёт от разыменования указателя на нул и соответственно сегфолта.

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

Что-то я не припомню, чтобы в этом топике мы с вами дискутировали. Я смотрю вы решили на личности перейти? Аргументы по существу отсутствуют?

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

Технически правильно, но если ошибок мало, branch predictor будет редко ошибаться.

Если действительно думать про оптимизацию, то проверка, которой нет, всегда однозначно лучше. Другое дело, что в реальном коде оверхед от растовского подхода в принципе не будет заметен, а действительно узкие места можно и оптимизировать. Я сам на С++ завел себе аналоги Error/Result, т.к. это удобно для публичных интерфейсов. В то время как в реализации бывает приятней работать с исключениями. Так что чем больше вариантов, тем лучше.

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

И наличие ссылок никак не спасёт от разыменования указателя на нул и соответственно сегфолта.

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

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

Я знаю и где можно, то стараюсь использовать ссылки, но проблема в том, что все мы люди, а компилятор не гарантирует, что в момент разыменования у тебя нормальный указатель.
Да, есть unique_ptr и shared_ptr, да они очень помогают. Но опять же мы не живём в идеальном мире и есть куча легаси в которых не то что unique_ptr, но бывает встречается собственные реализации векторов. Ну и вызовы сишных библиотек.
Один раз пропустил проверку на NULL, считай заложил мину.

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

Выравнивание включено по умолчанию, это так. Я имел в виду, что может случиться ситуация, когда enum rtype увеличит размер структуры на большее число байтов, чем sizeof(rtype) в результате паддинга.

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

Так конечный тип тоже выравнивается. Т.е. они все по умолчанию выравниваются на машинное слово.
Т.е. Result<rtype,etype> выровнен 'by default'.

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

Это бред. При копировании Result туда-обратно тебе не надо предсказаний вообще, а при разворачивании Result я получаю одно сравнение и один условный переход, которые я и так получил бы, решив проверить error code, пиши я на С/С++. А еще для избегания лишних проверок, если ты так боишься замедления, можешь использовать unwrap_unchecked. Никаких сравнений и условных переходов, разве что с привкусом швятого UB в случае если Result все же Err.

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

разыменования указателя на нул

А это плохо для системного языка??? Работа с памятью не может начинаться с нуля?? «Ядро», «загрузчико», «прошивка», «аппаратная виртуализация памяти» - не слышал не?!

и соответственно сегфолта

На чтение слова из памяти??? Сегфолт зависит от ОС а не языка. Он может вызываться даже на корректный случай, когда с точки зрения языка и аппаратной платформы делаешь все верно. Например, выделил кусок, засунул туда пару простых инструкций, вызвал его, вернулся, а потом освободил, но все равно получаешь сегфолт?! Потому что не все ОС могут иметь возможность выделять исполняемую память, не смотря на аппаратную защиту с привелегиями и ограничения прав со стороны ОС. А как тогда сделать JIT компилятор или сделать свою виртаулку??? А как тогда сделать антивирус?

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

Сам себе придумал тезис. Сам его опроверг. Молодец!

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

nullptr и 0 это разные вещи.

В расте нет. У них оптимизация типа enum {smth, smth2(&t)} реализуется через простой указатель, в котором 0 означает smth. Если нужно по нулевому адресу обращаться - только через ансейф указатели.

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

Все программирование на раст и состоит с бесконечных вызовов [inline]unwrap[/inline] и ему подобных, а также кастыля lazy_static! который растоводы юзают довольно часто, судя по пакетам в crates.io. Что КАГБЭ НАМЕКАЭ на красоту языка.

И вся простота языка превращается в настоящий квест по написанию работающего кода, особенно весело начинается когда такой решил перейти на многопоточность.

Еще доставялет реализация структур данных на расте. Особенно бинарное дерево. Казалось бы задачка для джуниора на собеседовании для сишнака.

[code]

// # derive(PartialEq) struct Node<’a> { val: &’a str, l: Option<Box<Node<’a>>>, r: Option<Box<Node<’a>>>, } impl<’a> Node<’a> { pub fn insert(&mut self, new_val: &’a str) { if self.val == new_val { return } let target_node = if new_val < self.val { &mut self.l } else { &mut self.r }; match target_node { &mut Some(ref mut subnode) => subnode.insert(new_val), &mut None => { let new_node = Node { val: new_val, l: None, r: None }; let boxed_node = Some(Box::new(new_node)); *target_node = boxed_node; } } } }

[/code]

С моим 1-2 года опыта на раст, даже я без подсказки не догадаюсь что это простое бинрное дерево без ссылки на родителя и без дженериков. А если будет ссылка на родителя, а еще с дженериком. УУУУУУУУУУ вот это будет веселье.

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

unwrap’ы бесят, это правда. Но если нормально описать Result, то сахарок ? очень хорошо заворачивает это дело делая похожим на исключения. lazy_static! скорее от незнания или лени, видимо его действительно не хватает нативно.

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

Не работает LORCODE кароч

Вот бинарное дерево на раст. Именно этот код и ему подобным сразу отбили желания ставить на раст.

#[derive(PartialEq)]
struct Node<'a> {
    val: &'a str,
    l: Option<Box<Node<'a>>>,
    r: Option<Box<Node<'a>>>,
}
impl<'a> Node<'a> {
    pub fn insert(&mut self, new_val: &'a str) {
        if self.val == new_val {
            return
        }
        let target_node = if new_val < self.val { &mut self.l } else { &mut self.r };
        match target_node {
            &mut Some(ref mut subnode) => subnode.insert(new_val),
            &mut None => {
                let new_node = Node { val: new_val, l: None, r: None };
                let boxed_node = Some(Box::new(new_node));
                *target_node = boxed_node;
            }
        }
    }
}

Я из тех людей которые всеръез задумывались о вакансиях. Кароч, с растом я буду голодным. Этот язык никому нафиг не нужен. Чисто как хобби.

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

Вот бинарное дерево на раст.

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

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

А что непонятно-то в коде?

Код старый, кстати. Сейчас можно писать Some(subnode) => subnode.insert(new_val)

Ну и вместо Node<'a> можно было написать GNode<T> и type Node<'a> = GNode<&'a str>;, если на одиночные кавычки аллергия.

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

где растут?! 2,5 проекта от левых кантор на пару месяцев и крутись как можешь. А всякие мозилы и прочее.

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

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

Кто-нибудь может внятно сформулировать что не нравится?

То, что раст-код относительно часто вызывает реакцию «Ах, ух, мерзость», это, конечно, неприятно. Но исправить ситуацию не поможет.

Впрочем, реальная частота такой реакции под вопросом. Те, кому синтаксис немного понравился/безразличен вряд ли будут об этом писать.

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

Вакансии под раст есть, в основном это крипта.

T.e. если мне как программисту крипта, как собаке пятая нога, то и Rust нафиг не нужен?

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

После пропускания через rustfmt

#[derive(PartialEq)]
struct Node<'a> {
    val: &'a str,
    l: Option<Box<Node<'a>>>,
    r: Option<Box<Node<'a>>>,
}

impl<'a> Node<'a> {
    pub fn insert(&mut self, new_val: &'a str) {
        if self.val == new_val {
            return;
        }
        let target_node = if new_val < self.val {
            &mut self.l
        } else {
            &mut self.r
        };
        match target_node {
            &mut Some(ref mut subnode) => subnode.insert(new_val),
            &mut None => {
                let new_node = Node {
                    val: new_val,
                    l: None,
                    r: None,
                };
                let boxed_node = Some(Box::new(new_node));
                *target_node = boxed_node;
            }
        }
    }
}
Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от baist

О боже, а это еще что значит?

*target_node = boxed_node;

Я когда увидел эту строку, подумал, что кто-то код с С’шки переписывал и забыл строку переписать/удалить.

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

Эта строка то же и означает, что в сишке) Только там (ненулевая и валидная) ссылка вместо указателя

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

А как по мне, так очень даже читабельно. Здесь лайфтаймы порядком загромождают код, с дженериками чище будет выглядеть. Попросить трейтT: Ord + Eq и все &'a str заменить на T, лайфтаймы вообще все можно будет убрать. #[derive(PartialEq)] вообще к дереву как таковому не относится, тоже можно было бы убрать ради чистоты.

Код в целом выходит декларативным. На хаскеле, конечно, красивее можно, но все же.

data BTree t = Empty | Branch t (BTree t) (BTree t)

insert :: (Ord t, Eq t) => t -> BTree t -> BTree t
insert l Empty =  Branch l Empty Empty
insert l (Branch m tr1 tr2) = if l == m 
                                then Branch m tr1 tr2
                                else if l < m
                                       then Branch m (insert l tr1) tr2
                                       else Branch m tr1 (insert l tr2) 

enum BTree<T: Ord + Eq> {
    Empty,
    Branch(T, Box<Self>, Box<Self>),
}

impl<T: Ord + Eq> BTree<T> {
    pub fn insert(&mut self, v: T) {
        match self {
            Self::Empty => {
                *self = Self::Branch(v, Box::new(Self::Empty), Box::new(Self::Empty))
            },
            Self::Branch(w, t1, t2) => {
                if &v == w {
                    return
                }
                if &v < w {
                    t1.insert(v);
                } else {
                    t2.insert(v);
                }
            }
        }
    }
}

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

Siborgium ★★★★★
()

В топе бездны баша в данный момент под номером 7 висит прекрасное:

opennet

Аноним (7): Спасибо языку Rust, я стал большим поклонником C++, теперь его считаю удобным и красивым языком

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

в основном это крипта.

Говно всякое, иными словами.

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

Иными словами:

«There are only two kinds of languages: the ones people complain about and the ones nobody uses.» (c) Bjarne Stroustrup, The C++ Programming Language

:)

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

Именно. Вот другой оратор заявляет о популярности D, но кто о нём слышал на лоре. Другое дело раст.

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

Кто-нибудь может внятно сформулировать что не нравится?

Низкая выразительность. К примеру, на С++ это может выглядеть так:

struct Node {
    string s;
    unique_ptr<Node> l;
    unique_ptr<Node> r;

    void insert( const string& value ) {
        if( value == s )
            return;

        if( auto& node = value < s ? l : r )
            node->insert( value );
        else
            node.reset( new Node { value } );
    }
};

От убийцы С++ я ожидал бы что-то вроде:

struct Node {
    s: String
    l: Node?
    r: Node?

    fn insert( value: String& ) {
        if( value == s )
            return

        if( node = value < s ? l : r )
            node->insert( value )
        else
            node = { s: value }
    }
};

Семантика и производительность та же, синтаксис поприятней. Я не собираюсь спорить с тем как написан код на Rust, я понимаю каждый момент по отдельности, почему вот так, а не так. Но в целом получается не так человечно, как в каком-нибудь Swift, например,

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

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

«Серебрянной пули не существует»

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

И то что ты мог делать на Си в одну строку не задумываясь

Если делаешь что-то большее чем hello_world.c, то оказывается, что в сишечке приходится много о чём задумываться. Особенно при выделении и высвобождении памяти. Имеется опыт переписывания с гольной сишечки на Rust. По итогу код оказался проще и приятней для чтения, чем гольная сишечка.
С плюсами там другой коленкор, многопоточные вещи лучше получаются,imho. Особенно понравились каналы. Ну а теперь ещё и async/await появился.

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

То, что в С является неявным контрактом, нарушение которого приводит ко всяким неприятным вещам, в раст выражается явно.

В данном случае это: 0-ptr - означает отсутствие значения (в расте - Option), указатели в node - владеющие (в расте - Box), указатель на строку нельзя использовать после деаллокации строки (в расте 'a), отсутствие алиасинга указателей в дереве (в расте - Box), недопустимость data race при вставке значения (в расте - &mut). Возможно что-то ещё.

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

Вот кстати есть вещи которые в Rust меня вымораживают. Почему impl<T: Ord + Eq> BTree<T> {, а не impl BTree<T: Ord + Eq> { или impl BTree<T> where T: Ord + Eq {?

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

Особенно при выделении и высвобождении памяти.

В ЯП C нет динамического выделения и высвобождения памяти. Библиотичные функции malloc/free могут быть какими угодно(с автоматической очисткой мусора, ага), могут не быть вообще(как и любые другие функции). Все зависит от реализации. Идея С - что у тебя есть возможность адресации по памяти и операции над потоком байт. А это int или float или просто 32битный указатель - один хрен - набор битов.

Это переносимый ассемблер. На уровне машиных команд все явлется потоком един и нулей. Текст/не_текст один хрен

А про динамическое выделение памяти речи не шло изначально. Вот в С++, да, там это на уровне языка.

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