Команда Rust рада сообщить о новой версии языка — 1.78.0. Rust — это язык программирования, позволяющий каждому создавать надёжное и эффективное программное обеспечение.
Если у вас есть предыдущая версия Rust, установленная через rustup
, то для обновления до версии 1.78.0 вам достаточно выполнить команду:
$ rustup update stable
Если у вас ещё не установлен rustup
, вы можете установить его с соответствующей страницы нашего веб-сайта, а также посмотреть подробные примечания к выпуску на GitHub.
Если вы хотите помочь нам протестировать будущие выпуски, вы можете использовать канал beta (rustup default beta
) или nightly (rustup default nightly
). Пожалуйста, сообщайте обо всех встреченных вами ошибках.
Что стабилизировано в 1.78.0
Диагностические атрибуты
Теперь Rust поддерживает пространство имён атрибутов #[diagnostic]
, что позволяет влиять на сообщения об ошибках компилятора. Теперь они рассматриваются как подсказки, которые компилятор не должен использовать. Также это не ошибка, предоставляющая диагности��у, которую компилятор не распознаёт. Такая гибкость позволяет исходному коду предоставлять диагностику, даже если она не поддерживается всеми компиляторами, будь то разные версии или совершенно разные реализации компилятора.
В этом пространстве имён появляется первый поддерживаемый атрибут #[diagnostic::on_unimplemented]
, который можно применить к трейту для настройки сообщения, которое отобразится, когда этот трейт требуется, но не реализован у типа. Рассмотрим пример, приведённый в запросе на стабилизацию:
#[diagnostic::on_unimplemented(
message = "My Message for `ImportantTrait<{A}>` is not implemented for `{Self}`",
label = "My Label",
note = "Note 1",
note = "Note 2"
)]
trait ImportantTrait<A> {}
fn use_my_trait(_: impl ImportantTrait<i32>) {}
fn main() {
use_my_trait(String::new());
}
Ранее компилятор выдал бы такую встроенную ошибку:
error[E0277]: the trait bound `String: ImportantTrait<i32>` is not satisfied
--> src/main.rs:12:18
|
12 | use_my_trait(String::new());
| ------------ ^^^^^^^^^^^^^ the trait `ImportantTrait<i32>` is not implemented for `String`
| |
| required by a bound introduced by this call
|
Теперь с помощью #[diagnostic::on_unimplemented]
пользовательское сообщение заполняет основную строку ошибки, а пользовательская метка помещается в исходный вывод. Исходная метка по-прежнему записывается как справочная информация, а также записываются все пользовательские примечания (эти данные могут быть изменены).
error[E0277]: My Message for `ImportantTrait<i32>` is not implemented for `String`
--> src/main.rs:12:18
|
12 | use_my_trait(String::new());
| ------------ ^^^^^^^^^^^^^ My Label
| |
| required by a bound introduced by this call
|
= help: the trait `ImportantTrait<i32>` is not implemented for `String`
= note: Note 1
= note: Note 2
Для авторов типажей такой вид диагностики более полезен, потому что с его помощью можно дать более подробную подсказку, чем просто писать об отсутствующей реализации. В качестве примера ниже показан сокращённый образец из стандартной библиотеки:
#[diagnostic::on_unimplemented(
message = "the size for values of type `{Self}` cannot be known at compilation time",
label = "doesn't have a size known at compile-time"
)]
pub trait Sized {}
Дополнительные сведения смотрите в справочном разделе о пространстве имён атрибута diagnostic
.
Проверка предусловий unsafe
Стандартная библиотека Rust содержит ряд утверждений для предварительных условий unsafe
функций, но исторически они были включены только в сборках стандартной библиотеки при помощи #[cfg(debug_assertions)]
, чтобы избежать влияния на производительность release сборки. Однако, поскольку стандартная библиотека обычно компилируется и распространяется с release профилем, большинство разработчиков Rust вообще никогда не выполняют эти проверки.
Теперь выполнение условий для этих проверок откладывается до генерации кода, поэтому они будут проверяться в зависимости от собственных настроек пользователя для отладочных проверок, включённых по умолчанию в отладочных и тестовых сборках. Это изменение помогает пользователям отслеживать неопределённое поведение в своём коде, хотя информация о том, сколько всего проверяется, как правило, не является стабильной.
Например, slice::from_raw_parts
требует выровненный ненулевой указатель. Следующее использование намеренно смещённого указателя приводит к неопределённому поведению и, хотя это может не иметь очевидных последствий, debug-проверка теперь может перехватить его:
fn main() {
let slice: &[u8] = &[1, 2, 3, 4, 5];
let ptr = slice.as_ptr();
// Создание отступа от `ptr` что всегда будет единственным отличием от корректного смещения `u16`
let i = usize::from(ptr as usize & 1 == 0);
let slice16: &[u16] = unsafe { std::slice::from_raw_parts(ptr.add(i).cast::<u16>(), 2) };
dbg!(slice16);
}
thread 'main' panicked at library/core/src/panicking.rs:220:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread caused non-unwinding panic. aborting.
Детерминированное повторное выравнивание
В стандартной библиотеке есть несколько функций, которые изменяют выравнивание указателей и срезов. Раньше в их использовании было несколько оговорок, из-за которых на практике полагаться на них было трудно, особенно если вы точно следовали документации. Эти предостережения в первую очередь существовали как страховка от вычисления const
, но в любом случае они были стабильны только для использования вне const
. Теперь обещано, что они будут иметь согласованное поведение во время выполнения в соответствии с фактическими входными данными
pointer::align_offset
вычисляет смещение, необходимое для изменения указателя на заданное выравнивание. Эта функция возвращаетusize::MAX
, если смещение невозможно, хотя раньше ей было разрешено всегда возвращатьusize::MAX
. Теперь такое поведение удалено.
Функции
slice::align_to
иslice::align_to_mut
преобразуют срезы в выровненный срез средней части данных и невыровненные головной и хвостовой. Теперь они обещают возвращать максимально возможную среднюю часть — вместо того, чтобы позволять реализации возвращать что-то менее оптимальное. Например, возвращать всё в виде головного среза.
Стабилизированные API
impl Read for &Stdin
В зависимости от реализации разрешены не-'static
времена жизни для некоторыхstd::error::Error
impl<Fd: AsFd>
имплементирует?Sized
impl From<TryReserveError> for io::Error
Следующие API теперь можно использовать в контексте const
:
Замечания о совместимости
- Как ранее анонсировалось, в Rust 1.78 поднимается минимальное требование до Windows 10 для следующих целевых платформ:
x86_64-pc-windows-msvc
i686-pc-windows-msvc
x86_64-pc-windows-gnu
i686-pc-windows-gnu
x86_64-pc-windows-gnullvm
i686-pc-windows-gnullvm
- В Rust 1.78 обновлён встроенный LLVM до версии 18, завершено изменение ABI для
u128
/i128
для x86-32 и x86-64 платформ. Дистрибьюторы, которые используют свою собственную LLVM старше 18 лет, всё ещё могут сталкиваться с ошибками в соглашении о вызовах, упомянутыми в этом посте.
Прочие изменения
Проверьте всё, что изменилось в Rust, Cargo и Clippy.
Кто работал над 1.78.0
Многие люди собрались вместе, чтобы создать Rust 1.78.0. Без вас мы бы не справились. Спасибо!
От переводчиков
С любыми вопросами по языку Rust вам смогут помочь в русскоязычном Телеграм-чате или же в аналогичном чате для новичковых вопросов. Если у вас есть вопросы по переводам или хотите помогать с ними, то обращайтесь в чат переводчиков.
Данную статью совместными усилиями перевели blandger, andreevlex, TelegaOvoshey и funkill.