Команда разработчиков Rust рада сообщить о выпуске новой версии, 1.38.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.
Если вы установили предыдущую версию Rust средствами rustup, то для обновления до версии 1.38.0 вам достаточно выполнить следующую команду:
rustup update stable
Если у вас ещё не установлен rustup, вы можете установить его с соответствующей страницы нашего веб-сайта.
Что вошло в стабильную версию?
Изюминка данного выпуска — конвейерная компиляция.
Конвейерная компиляция
Компилятору нужны не полностью собранные зависимости для сборки пакета, а лишь их "метаданные" (список типов, зависимостей, экспортов и т.д.), генерируемые на ранней стадии компиляции. Начиная с Rust 1.38.0, Cargo будет сразу же начинать сборку зависимых пакетов, как только их метаданные будут доступны.
Время сборки одного пакета не уменьшилось, но наши тесты показали, что скорость компиляции возрастает на 10%-20% в случае оптимизированных сборок (где некоторые зависимости уже скомпилированы). Для других же пакетов сильного прироста скорости компиляции не произошло. Время, необходимое для сборки пакета, зависит от компьютера, поэтому показатели могут отличаться. Конвейерная компиляция включена автоматически с версии 1.38.0.
Проверка некоторых неправильных использований mem::{uninitialized, zeroed}
Как ранее анонсировалось, std::mem::uninitialized
не рекомендуется к применению. Вместо неё должен использоваться MaybeUninit<T>
.
Функция mem::uninitialized
ещё не обозначена устаревшей, но это будет сделано в следующих выпусках. Но несмотря на это, начиная с 1.38.0, rustc
совершает проверку для узкого класса неправильных инициализаций с использованием mem::uninitialized
или mem::zeroed
.
Для некоторых типов, таких как &T
и Box<T>
, нулевое значение считается неопределённым поведением, так как они представляют собой подобные указателю объекты, которые не должны быть null
. Будет ошибкой использовать mem::uninitialized
или mem::zeroed
для инициализации этих типов, поэтому компилятор будет пытаться предупредить вас, если какая-либо из этих функций используется для инициализации указанных выше объектов, и не важно, будут ли они инициализированы напрямую или в качестве поля большой структуры. Данная проверка рекурсивная, так что следующий код влечёт за собой предупреждение:
struct Wrap<T>(T);
struct Outer(Wrap<Wrap<Wrap<Box<i32>>>>);
struct CannotBeZero {
outer: Outer,
foo: i32,
bar: f32
}
...
let bad_value: CannotBeZero = unsafe { std::mem::uninitialized() };
Внимательные читатели могут заметить, что стандартная библиотека содержит больше типов, которые не должны быть заполнены нулями, особенно NonNull<T>
и NonZero<T>
. Пока что инициализация этих структур посредством mem::uninitialized
или mem::zeroed
не проверяется.
Данные проверки не покрывают все случаи ненадлежащего использования mem::uninitialized
или mem::zeroed
, но позволяют обнаружить гарантированно неверный код, который должен перейти на использование MaybeUninit
.
#[deprecated]
для макросов
Атрибут #[deprecated]
, впервые представленный в Rust 1.9.0, позволяет авторам пакетов уведомлять пользователей об устаревающей функциональности, которую планируется удалить в последующих выпусках. Rust 1.38.0 позволяет применять данный атрибут и для макросов.
std::any::type_name
Строковое представление используемого типа может понадобиться при отладке кода. Например, в теле обобщённой функции вы можете захотеть напечатать тип переданного аргумента. Теперь это осуществимо посредством std::any::type_name
:
fn gen_value<T: Default>() -> T {
println!("Initializing an instance of {}", std::any::type_name::<T>());
Default::default()
}
fn main() {
let _: i32 = gen_value();
let _: String = gen_value();
}
Результат:
Initializing an instance of i32
Initializing an instance of alloc::string::String
Как и все функции стандартной библиотеки, предназначенные только для отладки, данная функция точное содержание и формат строки не гарантирует. Возвращаемое значение является лучшим описанием типа; несколько типов могут быть представимы одним и тем же type_name
, но оно может измениться в будущих версиях компилятора.
Изменения в стандартной библиотеке
slice::{concat, connect, join}
в дополнение к&T
теперь принимают и&[T]
.*const T
и*mut T
теперь реализуютmarker::Unpin
.Arc<[T]>
иRc<[T]>
теперь реализуютFromIterator<T>
.iter::{StepBy, Peekable, Take}
теперь реализуютDoubleEndedIterator
.
Кроме того, некоторые функции были стабилизированы:
<*const T>::cast
и<*mut T>::cast
Duration::as_secs_f32
иDuration::as_secs_f64
Duration::div_f32
иDuration::div_f64
Duration::from_secs_f32
иDuration::from_secs_f64
Duration::mul_f32
иDuration::mul_f64
- Евклидовы операции деления и получения остатка (
div_euclid
,rem_euclid
) для всех целочисленных примитивов. Версииchecked
,overflowing
иwrapping
также доступны.
Другие изменения
Синтаксис, пакетный менеджер Cargo и анализатор Clippy также претерпели некоторые изменения.
Участники 1.38.0
Множество людей собрались вместе, чтобы создать Rust 1.38.0. Мы не смогли бы сделать это без всех вас, спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов.
Данную статью совместными усилиями перевели andreevlex, nlinker, funkill и Gymmasssorla.
MooNDeaR
Можно поподробнее, что такое "конвейерная компиляция"?
ozkriff
Т.е. сборка пакетов с зависимостями будет начинаться до того, как все их зависмости будут собраны до конца. При большом количестве рекурсивных зависимостей это может заметно ускорять сборку.
(из IRLO темы)
MooNDeaR
Ок, теперь понял. Спасибо)