LINUX.ORG.RU

Вышел Rust 1.20

 


2

7

Команда разработчиков Rust с удовольствием объявляет о выходе новой стабильной версии Rust: 1.20.0.

Rust — это язык программирования, ориентированный на безопасность, скорость и параллелизм.

Если у вас установлена предыдущая версия Rust, то для обновления до Rust 1.20 достаточно выполнить следующую команду:

rustup update stable

(Прим. пер. - иногда предварительно нужно выполнить rustup self update)

Если Rust ещё не установлен, то вы можете установить его скачав rustup с соответствующей страницы на нашем сайте. Также вы можете посмотреть полный список изменений в Rust 1.20.0 на GitHub.

Что нового в стабильной версии Rust 1.20.0

В предыдущих версиях Rust вы уже могли определять «ассоциированные функции» для трейтов, структур и типов-сумм:

struct Struct;

impl Struct {
    fn foo() {
        println!("foo - это ассоциированная функция структуры Struct");
    }
}

fn main() {
    Struct::foo();
}

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

В Rust 1.20 добавлена возможность использовать «ассоциированные константы»:

struct Struct;

impl Struct {
    const ID: u32 = 0;
}

fn main() {
    println!("ID структуры Struct: {}", Struct::ID);
}
Здесь константа ID ассоциирована со структурой Struct. Как и функции, ассоциированные константы могут быть определены для трейтов и типов-сумм.

Использование ассоциированных констант в трейтах предоставляет дополнительные возможности. Ассоциированная константа в трейте используется также, как и ассоциированный тип: её можно определить, не присваивая ей значение. Значение константы будет указано при реализации трейта:

trait Trait {
    const ID: u32;
}

struct Struct;

impl Trait for Struct {
    const ID: u32 = 5;
}

fn main() {
    println!("{}", Struct::ID);
}
В предыдущих релизах Rust при реализации трейта, представляющего числа с плавающей точкой, приходилось писать такой код:
trait Float {
    fn nan() -> Self;
    fn infinity() -> Self;
    ...
}
Это немного неудобно, но, что более важно, такие функции невозможно использовать для определения констант. Из-за этого приходилось вводить дополнительные константы:
mod f32 {
    const NAN: f32 = 0.0f32 / 0.0f32;
    const INFINITY: f32 = 1.0f32 / 0.0f32;

    impl Float for f32 {
        fn nan() -> Self {
            f32::NAN
        }
        fn infinity() -> Self {
            f32::INFINITY
        }
    }
}
Ассоциированные константы позволяют реализовать всё это намного проще. Трейт будет выглядеть таким образом:
trait Float {
    const NAN: Self;
    const INFINITY: Self;
    ...
}
А его реализация станет намного проще и расшит возможности использования трейта:
mod f32 {
    impl Float for f32 {
        const NAN: f32 = 0.0f32 / 0.0f32;
        const INFINITY: f32 = 1.0f32 / 0.0f32;
    }
}
Ассоциированные константы были предложены три года назад в RFC 195. И мы наконец смогли их реализовать! Этот RFC содержал все виды ассоциированных элементов, не только константы. Некоторые из них мы смогли реализовать быстрее чем другие. Мы много работаем над улучшением поддержки работы с константными выражениями, чтобы увеличить возможности Rust в области мета-программирования во время компиляции. В будущем в этой области появятся дополнительные возможности.

Кроме того, мы исправили ошибку при работе с макросом include! в тестах документации: пути к файлам определялись относительно рабочего каталога, а не каталога, в котором находится файл кода.

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

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

Макро unimplemented! теперь принимает параметр, в котором можно указать причину отсутствия реализации.

Добавлена поддержка Unicode 10.0.0.

Функции min и max были переписаны на Rust, и больше не используют cmath.

Внедрена защита от уязвимости Stack Clash. Основные изменения: stack probes и отключение дополнительных ручных проверок для стека основного потока. Для включения защиты достаточно скомпилировать проект в Rust 1.20, изменения в коде не требуются.

В стандартную библиотеку добавлены три новые функции сортировки: slice::sort_unstable_by_key, slice::sort_unstable_by и slice::sort_unstable. Как вы заметили, все три содержат «unstable» в названиях. Стабильность — это свойство алгоритма сортировки, которое требуется не всегда, но раньше в стандартной библиотеке не было алгоритмов нестабильной сортировки. Теперь доступны обе возможности! Для демонстрации разницы между этими видами сортировки рассмотрим список:

rust
crate
package
cargo
Список, отсортированный алгоритмом стабильной сортировки только по первой букве, должен выглядеть таким образом:
crate
cargo
package
rust
То есть, если в исходном списке слово crate предшествовало слову cargo, то и в отсортированном списке оно должно стоять первым. Алгоритм нестабильной сортировки тоже может выдать такой результат, но допускается и вариант с измененной последовательностью:
cargo
crate
package
rust
Как вы понимаете, меньшее количество ограничений часто позволяет создать более быстрый алгоритм. Если вам не важна стабильность сортировки, нестабильная сортировка может оказаться быстрее, чем стабильный вариант. Как обычно, лучше попробовать оба варианта и сравнить их скорость. Эти функции сортировки были добавлены в RFC 1884. По ссылке вы можете узнать больше подробностей, включая результаты бенчмарков.

Также были стабилизированы следующие API:

и некоторые другие.

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

Этот релиз внес полезные улучшения в менеджер пакетов cargo. Первое и самое важное: токен аутентификации для crates.io хранился в ~/.cargo/config. Обычно маска доступа для файлов конфигурации устанавливается в 644, то есть чтение разрешено всем. Но в этом файле хранится секретный токен. Мы переместили токен в отдельный файл ~/.cargo/credentials, таким образом для него может быть установлен доступ 600, и он будет скрыт от других пользователей системы.

Если вы использовали пакеты Cargo, создающие дополнительные исполняемые файлы, вы знаете, что их исходный код хранится в src/bin. Но иногда вам может понадобиться создать несколько дополнительных исполняемых файлов, требующих много кода. В этом случае код может храниться в файлах src/bin/client.rs и src/bin/server.rs и все субмодули этих файлов попадут в один каталог, что неудобно и создает путаницу. Теперь мы используем соглашение, что такие файлы как src/bin/server/main.rs и src/bin/client/main.rs также используются для создания дополнительных исполняемых файлов. Это позволяет удобнее разграничить код.

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

Основной фишкой иммутабельности является так называемая «персистентность» (см. в Гугле), когда новый объект может разделять до 99,99% старого, а для этого по-хорошему нужен сборщик мусора, потому как на «умных» указателях будет просто медленнее работать. Даже замеры проводились (см. в Гугле опять же - мне лень).

Так что, вкусить все прелести иммутабельности никак не получится ни на Си, ни на Си++, ни на Rust. Такая вот селяви

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

Афигеть, дайте два! Да вы прям жгете напалмом.

Хо-хо-хо, пардон, мой косяк. Признаю.

Последний раз когда интересовался D, там было всё плохо, внезапно, он стал более продвинут о_О

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

Если верить Wikipedia, то «17 December 2003 – release of Linux kernel 2.6.0». В 2003-ем году D был еще сильно в нестабильном и сильно зачаточном состоянии. Может в нем еще даже шаблонов не было, т.к. изначально Брайт очень негативно к ним относился.

Можно сказать, что вы пропустили чуть ли не 15 лет в развитии языка :)

UPD. Шаблоны добавили в D в сентябре 2002-го, в D.040. А потом еще неоднократно их доводили до ума.

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

Так уж плохо? Подсчёт ссылок легко заменяет GC при условии отсутствия циклов. В случае иммутабельности циклов быть не может.

Проблема производительности подсчёта ссылок серьёзна, но там основная проблема в атомарности счётчика, растовый Rc обходится без неё. Вторая проблема, поменьше, в операциях копирования, при передаче shared_ptr в функции производится копирование с последующим уничтожением копии, что лишний раз дёргает счётчик, а std::move везде писать неудобно. В Расте копирование Rc только явное, если функция на входе получает Rc и передаёт его глубже, всё через перемещение работает и счётчик никто не трогает.

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

Ну и что, вы по-прежнему уверены, что иммутабельность данных в Java есть?

вот я вам класс привел - поменяйте в его экземпляре значение foo.

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

Еще раз: в Java вы иммутабельность вынуждены делать руками. В C/C++/D модификатор const может быть применен к любому типу. Так что в D иммутабельность на уровне языка есть, а в Java — нет.

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

Про Rс я в курсе. Но еще часто бывает нужен RefCell.

А что странного в том, что на такой задаче GC будет работать быстрее, чем так называемые «умные указатели»? Вполне нормальная и ожидаемая ситуация.

Ведь просто так ничего не дается. Ну, а тезисы типа «zero cost abstraction» из Rust и «не платим за то, что не используем» из Си++ - не более, чем лозунги. Платим, и еще как платим.

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

Ну, и у GC тоже есть своя цена, и это нормально

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

Scala, например, кому-то нужна и особого дробления сообщества не замечено.

А там что регулярно ломают совместимость? Или речь о Dotty? Так оно ещё и не зарелизилось.

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

Про Rс я в курсе. Но еще часто бывает нужен RefCell.

Вроде про иммутабельность речь была, зачем RefCell?

А что странного в том, что на такой задаче GC будет работать быстрее, чем так называемые «умные указатели»? Вполне нормальная и ожидаемая ситуация.

Не уверен. Если атомарные счётчики - тогда да, если неатомарные и если учитывать GC, то бабушка надвое сказала.

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

Да, про RefCell зря добавил. Подумалось о другом.

Для однопоточного приложения Rc вполне неплох, но тоже не бесплатен. Там скорее, если приложение много работает, начинаются разные чудеса с фрагментацией и прочими вещами, из-за чего те же malloc и free начнут притормаживать. Да, и куда без потоков в наше время?!

И как известно, универсальных решений не существует ни в программировании, ни во многих других областям. В общем, повторюсь: «zero cost abstraction» - это лишь вожделенная мечта, хотя для некоторых частных случаев достижимая

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

В общем, повторюсь: «zero cost abstraction» - это лишь вожделенная мечта, хотя для некоторых частных случаев достижимая

Во второй раз: rc - не zero cost. А вот трейты - zero cost. Чувствуете разницу?

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

если приложение много работает, начинаются разные чудеса с фрагментацией и прочими вещами, из-за чего те же malloc и free начнут притормаживать

Когда кажется - крестится надо. GC сжимает кучу не за бесплатно.

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

Он так понял, что код вызывает рвоту, а предназначен для того, чтобы продемонстрировать мерзостность Rust. Считать так — его право, но на беду он еще и пытается это доказать всем вокруг.

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

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

Кстати, про зеро-кост брехня. Ценой здесь психическое здоровье пограмиста.

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

Говоря о zero cost человек (наверное) имеет ввиду то, что абстракции текут, особенно если они zero cost. Потому, призывает не фанатеть от этого и использовать GC, например, если так лучше.

vlad9486 ()