Выпуск Rust 1.20

оригинал: The Rust Core Team • перевод: red75prime и Илья Богданов • новости • поддержите на Patreon

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

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

1
$ rustup update stable

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

Что вошло в стабильную версию 1.20

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

1
2
3
4
5
6
7
8
9
10
11
struct Struct;

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

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

Мы называем их «ассоциированными функциями», потому что эти функции связаны непосредственно с самим типом, а не с каким-то определённым экземпляром.

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

1
2
3
4
5
6
7
8
9
struct Struct;

impl Struct {
    const ID: u32 = 0;
}

fn main() {
    println!("the ID of Struct is: {}", Struct::ID);
}

Таким образом, константа ID ассоциирована с Struct. Подобно функциям, ассоциированные константы работают и с типажами, и с перечислениями.

У типажей есть дополнительная возможность, полезная во многих ситуациях. Вы можете использовать ассоциированные константы также, как и ассоциированные типы: объявляя их, но не назначая никакого значения. Конкретное значение должно быть назначенным во время реализации типажа каким-либо типом.

1
2
3
4
5
6
7
8
9
10
11
12
13
trait Trait {
    const ID: u32;
}

struct Struct;

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

fn main() {
    println!("{}", Struct::ID);
}

До этого выпуска, если вы хотели написать типаж, представляющий числа с плавающей точкой, вам приходилось делать так:

1
2
3
4
5
trait Float {
    fn nan() -> Self;
    fn infinity() -> Self;
    ...
}

Это выглядит немного громоздко, но, что важнее, мы не могли использовать эти функции в константных выражениях, даже если функции и возвращали одно и то же значение. Из-за этого, Float также должен предоставлять и константы:

1
2
3
4
5
6
7
8
9
10
11
12
13
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
        }
    }
}

Ассоциированные константы позволяют сделать вам то же самое, но гораздо легче. Объявление типажа:

1
2
3
4
5
trait Float {
    const NAN: Self;
    const INFINITY: Self;
    ...
}

Реализация:

1
2
3
4
5
6
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! в тестах документации: пути к файлам определялись относительно рабочего каталога, а не каталога, в котором находится текущий файл.

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

Стабилизация стандартной библиотеки

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

Макрос unimplemented! теперь принимает параметр, позволяющий сообщить пользователю, по какой причине что-либо не было реализовано.

Мы обновили поддержку Unicode до версии 10.0.0.

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

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

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

1
2
3
4
rust
crate
package
cargo

Два слова из приведённых, cargo и crate, начинаются с буквы c. Список, отсортированный алгоритмом стабильной сортировки только по первой букве, должен выглядеть таким образом:

1
2
3
4
crate
cargo
package
rust

То есть, если в исходном списке слово crate предшествовало слову cargo, то и в отсортированном списке оно должно стоять первым. Алгоритм нестабильной сортировки тоже может выдать такой результат, но допускается и вариант с изменённой последовательностью:

1
2
3
4
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 также используются для создания дополнительных исполняемых файлов. Это позволяет удобнее разграничить код.

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

Разработчики 1.20.0

Множество людей участвовало в разработке Rust 1.20. Мы не смогли бы этого добиться без участия каждого из вас. Спасибо!