LINUX.ORG.RU

Rust 1.13

 


4

10

Представлен релиз Rust 1.13 — системного языка программирования, нацеленного на безопасную работу с памятью, скорость и параллельное выполнение кода. В этот релиз вошли 1448 патчей.

Этот сезон оказался очень плодотворным для Rust. Проведены конференции RustConf, RustFest и Rust Belt Rust. Обсуждено будущее языка, разработан план на 2017 год и созданы новые инструменты.

Новое в 1.13

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

Cargo в этом релизе содержит важные обновления безопасности, связанные с зависимостями от curl и OpenSSL, для которых также недавно были опубликованы обновления безопасности. Подробную информацию можно найти в соответствующих источниках для curl 7.51.0 и OpenSSL 1.0.2j.

Оператор ?

Добавлен новый оператор ?, делающий обработку ошибок приятнее за счёт уменьшения визуального шума. В качестве иллюстрации представим следующий код, который считывает некоторые данные из файла:

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("username.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

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

С оператором ?, вышестоящий код выглядит следующим образом:

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("username.txt")?;
    let mut s = String::new();

    f.read_to_string(&mut s)?;

    Ok(s)
}

Оператор ? заменяет весь код обработки ошибок, написанный при помощи оператора match ранее. Иными словами, ? применяется к значению Result, и если оно равно Ok, разворачивает его и отдаёт вложенное значение; если это Err, то происходит возврат из функции, в которой вы находитесь.

Более опытные пользователи могут заметить, что этот оператор делает то же самое, что и макрос try!, который доступен начиная с Rust 1.0. И будут правы, в самом деле, это то же самое. До 1.13 read_username_from_file можно было бы написать следующим образом:

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = try!(File::open("username.txt"));
    let mut s = String::new();

    try!(f.read_to_string(&mut s));

    Ok(s)
}

Так зачем надо было расширять язык, если до этого уже был такой макрос? Есть несколько причин. Во-первых, try! доказал своё огромное значение и часто используется в идеоматичном Rust. Он используется так часто, что было принято решение о создании собственного «подслащенного» синтаксиса для него. Такой вид эволюции — одно из преимуществ мощной системы макросов: расширения к синтаксису языка можно добавлять через прототипирование без внесения изменений в сам язык и особо полезные макросы могут указать на недостающие возможности языка. Эволюция try! в ? — яркий пример этого.

Другая причина — восприятие нескольких последовательных вызовов try!:

try!(try!(try!(foo()).bar()).baz())
против
foo()?.bar()?.baz()?

В первом случае, где каждый уровень обработки ошибки вызывает try!, код сложнее для восприятия и может отвлекать внимание от основного кода, как в данном случае.

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

Более подробно об операторе ? можно прочитать в RFC 243.

Улучшение производительности

В последнее время очень много внимания заострено на производительности компилятора. Mark Simulacrum и Nick Cameron произвели улучшения http://perf.rust-lang.org/, инструмента для отслеживания производительности компилятора, на котором периодически запускается набор rustc-benchmarks на выделенном оборудовании. Инструмент записывает результаты каждого прохода компилятора и позволяет находить и отслеживать код, приведший к регрессии. Например, при помощи этого инструмента можно посмотреть график производительности за весь цикл разработки релиза 1.13, где можно увидеть заметное сокращение времени работы компилятора, отдельно представленное на соответствующей странице со статистикой.

Большое улучшение на графике от 1 сентября связано с оптимизацией от Niko по кешированию нормализованных проекций во время преобразования. То есть во время генерации промежуточного представления LLVM компилятор больше не пересчитывает каждый раз конкретные экземпляры связанных типов, когда они необходимы, а использует ранее вычисленные значения. Несмотря на то, что данная оптимизация не влияет на всю кодовую базу, для некоторого кода с определенным шаблоном, например, futures-rs, ускорение сборки в режиме отладки достигает 40%.

Другая оптимизация от Michael Woerister уменьшает время компиляции библиотек, экспортирующих множество встраиваемых функций. Когда функция помечена как «#[inline]», в дополнение к преобразованию этой функции в текущей библиотеке компилятор сохраняет её представление MIR и преобразует функцию в представление LLVM в каждой библиотеке, которая вызывает её. Оптимизация, сделанная Michael Woerister, позволяет компилятору избегать предварительных преобразований кода встраиваемых функций в библиотеках, в которых они определены, до их непосредственного прямого вызова. Таким образом, компилятор избавляется от необходимости выполнения лишних шагов по преобразованию функции в промежуточное представление LLVM, оптимизации LLVM и преобразования функции в машинный код.

В некоторых случаях это приводит к впечатляющим результатам. Например, время сборки библиотеки ndarray уменьшилось на 50%, а библиотека winapi 0.3 (ещё не опубликована) полностью избавилась от шага генерации машинного кода.

Но это ещё не всё: Nick Nethercote обратил своё внимание на производительность компилятора, сконцентрировавшись на профилировании и микрооптимизациях. Этот релиз включает в себя некоторые плоды его работ, ещё больше ожидается в 1.14.

Другие заметные изменения

Макросы теперь можно использовать на позиции типов (RFC 873), а атрибуты могут быть применены к операторам (RFC 16):

// Use a macro to name a type
macro_rules! Tuple {
    { $A:ty,$B:ty } => { ($A, $B) }
}

let x: Tuple!(i32, i32) = (1, 2);

// Apply a lint attribute to a single statement
#[allow(uppercase_variable)]
let BAD_STYLE = List::new();

Были удалены встраиваемые флаги сброса. Раньше при условном перемещении компилятор встраивал «флаг сброса» в структуру (увеличивая его размер), чтобы отслеживать, когда надо его сбросить. Из-за этого некоторые структуры занимали больше места, что мешало передаче типов с деструкторами поверх FFI. Благодаря тому, что в версии 1.12 добавлен MIR, появилась основа для многих улучшений, включая удаление встраиваемых флагов сброса. Теперь флаги сброса хранятся в дополнительном слоте в стеке тех функций, которым они нужны.

Релиз 1.13 содержит серьёзную ошибку в генерации кода для ARM с аппаратной реализацией чисел с плавающей точкой. Поскольку 1.13 содержит исправление безопасности, пользователям ARM рекомендуется использовать бета-версии 1.14, в которых скоро появится исправление для ARM.

Стабилизация языка

Стабилизация библиотек

Возможности Cargo

Более детальный список изменений доступен по ссылке: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1130-2016-1...

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

★★★★★

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

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

Ты меня разоблачил!!!111

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

Как вариант - посмотрите в сторону FreeBSD-шной sys/queue.h, для списков, которые дальше упоминали по треду, очень удобная, имхо, вещь

Ёх! Как раз эта вещь используется сейчас, и текущее перетряхивание проекта связано в том числе с ее выкидыванием. Слишком удобно для меня (сарказм).

Нет в си обобщенного программирования, и хотя бы поэтому сабж нужен.

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

я в курсе, что рукожопам запрещено использовать ресурсы процессора эффективно.

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

Да RazrFalcon вообще самый настоящий сектант. Аккуратней с ним, а то он лопнет.

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

По моему, единственных кто его не хотел - это tailgunner.

Точно нет.

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

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

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

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

Читабельность любого ЯП для неспециалиста стремится к нулю.

Слишком вы категоричны.

Субъективная оценка соверненно никакой смысловой нагрузки не несет.

Когда фанату что-то неудобно, то он начинает юлить.

Если нет конкретных объективных претензий — лесом, пожалуйста.

Сравнительная характеристика вас не устроила?

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

Понимаю ли я, что подразумевают мои слова? Пока да. А вот вы видимо нет.

Да, я не понимаю. Поясните мне, пожалуйста, как синтаксис Rust-а может полностью совпадать с синтаксисом C++, если пример кода на Rust-е ну никак не похож на код на C++?

Сравнивать Rust и OCaml - это вообще прикол.

Ну кому прикол, а кому let mut сильно напоминает let rec. Ключевое слово type используется и там, и там. Ключевое слово match и там и там для паттерн-матчинга. if и там и там записывается без круглых скобочек для условий и if является выражением, а не оператором.

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

В фигурной скобочке и точке с запятой?

А разве они не являются частью синтаксиса?

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

как синтаксис Rust-а может полностью совпадать с синтаксисом C++

Про полностью речь и не шла. Но достаточно слегка поменять порядок выражений и получить C++ вариант. Перенос кода rust <-> c++ происходит очень легко. В то время как код на том же OCaml так просто не перенести.

Ключевое слово match и там и там для паттерн-матчинга. if и там и там записывается без круглых скобочек для условий и if является выражением, а не оператором.

И? Можно набрать еще больше примеров общего между C++ и Rust. Они от этого не становятся похожими?

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

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

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

Это смотря как мерять. Если по количеству фигурных скобок, то да, а если по количеству match - то нет.

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

Чота ржу с вашего анализа сходств и различий. Евгений вот нашел знакомые слова в окамле, ты похоже тоже. Пойду нашим макакам расскажу, что PHP - это Java, пусть требуют прибавки, лол.

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

Про полностью речь и не шла.

Как это не шла: «Начнём с того, что синтаксис раста совпадает с С++ чуть менее чем полностью.»

Или для вас русский не родной?

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

Чота ржу с вашего анализа сходств и различий.

Давно уже ни хера не смешно, а грустно с таких тупых ржущих в отчет на всё, что не понимают...

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

Чота ржу с вашего анализа сходств и различий

Это от невежества.

Пойду нашим макакам расскажу, что PHP - это Java

Да ладно, мы же понимаем, что идти тебе никуда не придется.

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

Конкретные претензии, а не высосанные из пальца то будут?

Пример: eao197, вон, считает, что вот это:

template<borrow A, borrow B>
tuple<borrow<A, int32>, borrow<B, int32>>
firsts(borrow<A, vector<int32>> x, borrow<B, vector<int32>> y)
Читабельнее, чем вот это:
fn firsts<'a, 'b>(x: &'a Vec<i32>, y: &'b Vec<i32>) -> (&'a i32, &'b i32)

Скажи, у вас это профессиональное заболевание или он один такой?

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

Давайте еще поговорим об отличии бесконечно малой величины от абсолютного нуля.

считает, что вот это:
Читабельнее, чем вот это:

Дать цитату на первоисточник и при этом соврать — это как? Надежда на то, что никто не проверит?

В первоисточнике было так:

Т.е. когда ты видишь что-то вроде:

fn firsts<'a, 'b>(x: &'a Vec<i32>, y: &'b Vec<i32>) -> (&'a i32, &'b i32)

то взгляд должен цепляться буквально за каждый символ, ибо здесь любая закорючка имеет значение. Думаю, что если бы использовался какой-то такой синтаксис, то ситуация была бы получше:

func firsts<borrow A, borrow B>(x: borrow<A> Vector<int32>, y: borrow<B> Vector<int32>) -> tuple<borrow<A> int32, borrow<B> int32>

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

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

Конкретные претензии, а не высосанные из пальца то будут?

Для меня уже одна ваша агрессия является маячком, «держись от раста как можно дальше».

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

как можно было бы сделать, если бы у создателей Rust-а была цель переманить в Rust С++ников.

Вывод: такая запись для C++ников более читабельна, не так ли?

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

попросил вместо невнятной вкусовщины более развернутое и обоснованное мнение
агрессия

Ясно.

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

В соседней теме про Rust стало очевидно, что вы не различаете синхронизацию и коммуникацию. Теперь становится понятно почему: скорее всего глупость. Другими причинами объяснить «такая запись для C++ников более читабельна, не так ли?» сложно.

Но специально для вас поясню еще раз (хотя в тексте все было уже описано): такой синтаксис, на мой взгляд, упростил бы переписывание уже существующего C++ кода на Rust.

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

как можно было бы сделать, если бы у создателей Rust-а была цель переманить в Rust С++ников.

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

lifetime<A, B>
firsts(A:Vec<i32> x, B:Vec<i32> y) -> (A:i32, B:i32)
anonymous
()
Ответ на: комментарий от eao197

переписывание уже существующего C++ кода на Rust.

Если вы считаете, что раст создан для того, чтобы на него переписывали существующие кодовые базы c C++ в лоб, то мне действительно больше нечего сказать, так как Вы, похоже, совсем не знаете о расте ничего.
Идиоматический безопасный раст-код не переписывается с C++ напрямую, если речь о архитектуре сложнее, чем у студенческих лаб.

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

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

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

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

Я считаю, что если бы у Rust-а был синтаксис, который бы позволил с минимальными усилиями преобразовать, скажем, вот такой C++ный код:

template<class ForwardIt, class T>
ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value)
{
    ForwardIt it;
    typename std::iterator_traits<ForwardIt>::difference_type count, step;
    count = std::distance(first, last);
 
    while (count > 0) {
        it = first; 
        step = count / 2; 
        std::advance(it, step);
        if (*it < value) {
            first = ++it; 
            count -= step + 1; 
        }
        else
            count = step;
    }
    return first;
}
в валидный Rust-код, то Rust-у было бы гораздо проще занять свое место под Солнцем, чем при его нынешнем синтаксисе.

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

Нормальные ОС возврщают ошибку ENOMEM.

Возвращают и успешно, после этого, виснут. Проверено и на linux и на windows.

Хреново быть маководом, чо.

Опять вы со своими странными фантазиями. Давайте, и я пофантазирую. Вы работаете «варгейминге». Угадал?

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

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

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

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

С чего бы? Прописал необходимые инструкции в требованиях к стилю кода и всё: весь персонал пишет на «С с классами».

Rust что-то новое в этой сфере предлагает?

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

невозможно запретить использование полного языка.

С чего бы? Прописал необходимые инструкции в требованиях к стилю кода и всё

Это и называется «невозможно».

Rust что-то новое в этой сфере предлагает?

А Rust пока не надо разбивать на подмножества. Но если понадобится, то да, предлагает: https://github.com/Manishearth/rust-clippy

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

Нормальные ОС возврщают ошибку ENOMEM.

Возвращают и успешно, после этого, виснут

Или, в случае Linux, не виснут.

Хреново быть маководом, чо.

Опять вы со своими странными фантазиями

Я вижу юзерагенты. Ты либо маковод, либо хочешь им быть.

Вы работаете «варгейминге». Угадал?

Нет.

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

Или, в случае Linux, не виснут.

Вполне себе. Не всегда намертво, но на ssd всегда быстрее перезагрузиться. На ide — как правило.

Я вижу юзерагенты.

В таком случае, вы должны были видеть, что у меня в течении 24 часов сменился не только UA, но ещё и ip. (предыдущий UA был линукс + лиса)

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

что у меня в течении 24 часов сменился не только UA, но ещё и ip

Ну да, ну да. Ты вообще здесь единственный анонимус.

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

Разфлакон весьма адекватен в этом ржавом шапито. Он уже даже начал сомневаться, так ли хорош брейнфак, как его рисуют. Кстати, тылганнер как матерый евангелист сам к расту не прикасается :D Мудрый чертяка.

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

&'a Vec<i32>

Ну кто так делает? &'a [i32] же. Да и зачем прибивать гвоздями к i32?
fn firsts<'a, 'b, T>(x: &'a [T], y: &'b [T]) -> (&'a T, &'b T)

func firsts<borrow A, borrow B>(x: borrow<A> Vector<int32>, y: borrow<B> Vector<int32>) -> tuple<borrow<A> int32, borrow<B> int32>

От того, что всё заменили словами, читаемость не поднялась. Даже, скорее, ухудшилась, так как запись стала длиннее.

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

Кто сказал? Какая ОС? Не замечал чтобы декстоп или мобилки перезагружались. Они убивают лишние приложения и продолжают работу.

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

И тут мы пришли к вкусовщине. Если вам там нравится писать кучу лишнего кода - пожалуйста.

Я вам даже больше скажу, можно и на расте писать и так как вы хотите:

fn check<T: Borrow<str>>(s: T) {
    assert_eq!("Hello", s.borrow());
}

fn is_hello<T: AsRef<str>>(s: T) {
   assert_eq!("hello", s.as_ref());
}

Только это дурной вкус.

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

И тут мы пришли к вкусовщине.

Синтаксис — это всегда вкусовщина.

Если вам там нравится писать кучу лишнего кода

Мне не нравится читать криптограммы.

можно и на расте писать и так как вы хотите

И как же в таком синтаксисе будет выглядеть прототип упомянутой выше функции firsts?

Только это дурной вкус.

Почему?

PS. Ну и по поводу «синтаксис раста совпадает с С++ чуть менее чем полностью» я так понимаю, что вы слились.

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

Для меня вариант на расте значительно более читабельнее. Просто потому что можно один взглядом охватить всю строку и все что нужно знать само за взгляд зацепится. А в варианте на с++, к которому я давно не прикасался, мне приходится долго и мучительно вчитываться в каждое слово и бегать туда-сюда взглядом чтобы понять что там делается.

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

Ну кто так делает?

Некто Jim Blandy, автор книжицы «Why Rust?». Вот, оттуда характеристика на автора:

Jim Blandy works for Mozilla on Firefox’s tools for web developers. He is a committer to the SpiderMonkey JavaScript engine, and has been a maintainer of GNU Emacs, GNU Guile, and GDB. He is one of the original designers of the Subversion version control system.

eao197 ★★★★★
()
Ответ на: комментарий от eao197
fn lower_bound<T, I>(mut iter: I, value: T) -> I
where T: Ord, I: Clone + ExactSizeIterator<Item=T>
{
    let mut count = iter.len();
    while count > 0 {
        let step = count / 2;
        let mut it = iter.clone();
        if it.nth(step).unwrap() < value {
            iter = it;
            count -= step + 1;
        } else {
            count = step;
        }
    }
    iter
}
anonymous
()
Ответ на: комментарий от eao197

Я считаю, что если бы у Rust-а был синтаксис, который бы позволил с минимальными усилиями преобразовать, скажем, вот такой C++ный код:

Но всем без разницы, что вы там считаете. Раст пишут не для вас, а для людей. У авторов раста не было целей сделать еще один C++, поэтому они ушли в сторону удобства.

Приведенный вами код по нормальному нельзя переписать, так как у раста нет RandomAccessIterator.

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

Не тоже самое, но близко. Особенно если ТС хочет всё руками писать.

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

я так понимаю, что вы слились.

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

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

Мне не нравится читать криптограммы.

То есть всякие :: . -> & * | >> вам прекрасно понятны, а как только появляется ' - язык сразу превращается в perl?

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