Команда 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



Следующие 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.

Комментарии (3)


  1. Mingun
    04.05.2024 07:55
    +10

    Не очень перевод в этот раз, какие-то инопланетные фразы, по которым вообще ничего не понятно.

    1

    Теперь они рассматриваются как подсказки, которые компилятор не должен использовать. Также это не ошибка, предоставляющая диагностику, которую компилятор не распознаёт.

    Чего? Не должен использовать? А в примере вывода вполне себе использует. Что в оригинале:

    These are treated as hints which the compiler is not required to use, and it is also not an error to provide a diagnostic that the compiler doesn't recognize.

    Правильный перевод будет таким:

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

    2

    // Создание отступа от `ptr` что всегда будет единственным отличием от корректного смещения `u16`

    А точно тут «единственным»? Оригинал:

    // Create an offset from `ptr` that will always be one off from `u16`'s correct alignment

    Конечно, нет. Должно быть:

    // Вычисляем отступ от `ptr`, на единицу меньший правильного выравнивания для `u16`

    3

    Эти предостережения в первую очередь существовали как страховка от вычисления const, но в любом случае они были стабильны только для использования вне const.

    Ничего не понятно. Что ещё за вычисление const? И что значит «вне const»? Оригинал (кстати, почему «оговорки» из предыдущего предложения внезапно стали «предостережениями»?):

    Those caveats primarily existed as a hedge against const evaluation, but they're only stable for non-const use anyway.

    «Правильный» перевод (правда, я не знаю Rust и не уверен полностью насчёт того, что здесь имеется в виду под const, предполагаю, что это «вычисления в константном контексте»):

    Эти оговорки в основном служили страховкой от вычислений в const-контексте, хотя указанные функции стабильны были всё равно только не в const-контексте.

    4

    Функции slice::align_to и slice::align_to_mut преобразуют срезы в выровненный срез средней части данных и невыровненные головной и хвостовой. Теперь они обещают возвращать максимально возможную среднюю часть — вместо того, чтобы позволять реализации возвращать что-то менее оптимальное. Например, возвращать всё в виде головного среза.

    Вроде и понятно, но очень косноязычно. Оригинал значительно понятнее:

    slice::align_to and slice::align_to_mut both transmute slices to an aligned middle slice and the remaining unaligned head and tail slices. These methods now promise to return the largest possible middle part, rather than allowing the implementation to return something less optimal like returning everything as the head slice.

    Понятный перевод:

    Функции slice::align_to и slice::align_to_mut разбивают срезы на части (до трёх штук): выровненную среднюю часть и невыровненные части по краям. Теперь они обещают возвращать среднюю часть наибольшего возможного размера. Ранее реализации могли возвращать что-то менее оптимальное — например, просто возвращать всё в виде первой невыровненной части.


  1. kovalensky
    04.05.2024 07:55

    Давно хочу стать растаманом, начинаю читать книгу, а они всё обновления да обновления.

    Страшно становится каждый раз :D


    1. 1755
      04.05.2024 07:55
      +1

      А что такого страшного в обновлениях?)