
Все детали и изменения, которые произошли с Rust 1.82.0
27 июля 2025 г.Команда Rust с радостью объявила о новой версии Rust, 1.82.0. Rust - это язык программирования, позволяющий всем создавать надежное и эффективное программное обеспечение.
Если у вас предыдущая версия Rust, установленная черезrustup
, вы можете получить 1.82.0 с:
$ rustup update stable
Если у вас его еще нет, вы можетеполучатьrustup
На соответствующей странице на нашем веб -сайте и проверьтеПодробные заметки о выпуске для 1.82.0Полем
Если вы хотите помочь нам, тестируя будущие релизы, вы можете рассмотреть возможность обновления локально для использования бета -канала (rustup default beta
) или ночной канал (rustup default nightly
) ПожалуйстаотчетЛюбые ошибки, с которыми вы можете встретить!
Что в 1,82,0 стабильно
cargo info
В грузе теперь естьinfo
подкоманда, чтобы отобразить информацию о пакете в реестре, выполняядавний запросПросто стесняется десятой годовщины! Несколько сторонних расширений были написаны на протяжении многих лет, и эта реализация была разработана какинформация грузаПрежде чем объединиться в сам груз.
Например, вот что вы могли бы увидетьcargo info cc
:
cc #build-dependencies
A build-time dependency for Cargo build scripts to assist in invoking the native
C compiler to compile native C code into a static archive to be linked into Rust
code.
version: 1.1.23 (latest 1.1.30)
license: MIT OR Apache-2.0
rust-version: 1.63
documentation: https://docs.rs/cc
homepage: https://github.com/rust-lang/cc-rs
repository: https://github.com/rust-lang/cc-rs
crates.io: https://crates.io/crates/cc/1.1.23
features:
jobserver = []
parallel = [dep:libc, dep:jobserver]
note: to see how you depend on cc, run `cargo tree --invert --package cc@1.1.23`
По умолчанию,cargo info
описывает версию пакета в локальномCargo.lock
, если есть. Как видите, это будет указывать, когда есть и более новая версия, иcargo info cc@1.1.30
сообщит об этом.
Apple Target Promotions
macOS на 64-битной руке теперь уровня 1
Цель ржавчиныaarch64-apple-darwin
Для MacOS на 64-битной руке (M1-семейство или более позднее яблочное кремниевое ЦП) теперь является целью 1-го уровня, что указывает на нашу самую высокую гарантию правильной работы. КакПоддержка платформыПейдж описывает, что каждое изменение в репозитории Rust должно проходить полные тесты на каждой цели уровня 1, прежде чем его можно будет объединить.
Эта цель была представлена как уровень 2 в Rust 1.49, что делает ее доступным вrustup
Полем Этот новый веха ставитaarch64-apple-darwin
Цель наравне с 64-битным ARM Linux и x86 MacOS, Linux и Windows.
Mac Catalyst Targets теперь уровня 2
MAC Catalystэто технология Apple, которая позволяет использовать приложения для iOS назначать на Mac. Это особенно полезно при тестировании специфичного для iOS, какcargo test --target=aarch64-apple-ios-macabi --target=x86_64-apple-ios-macabi
В основном просто работает (в отличие от обычных целей iOS, которые должны быть связаны с использованием внешнего инструмента, прежде чем их можно будет работать на собственном устройстве или в симуляторе).
Целитеперь уровень 2 и можно скачать сrustup target add aarch64-apple-ios-macabi x86_64-apple-ios-macabi
Так теперь отличное время для обновления вашего CI Pipeline, чтобы проверить, что ваш код также работает в средах, подобных iOS.
Точный захватuse<..>
синтаксис
Ржавчина теперь поддерживаетuse<..>
синтаксис внутри определенногоimpl Trait
границы для управления, какие общие параметры срока службы захвачены.
Поставка возвратаimpl Trait
(RPIT) Типы в ржавчинезахватыватьОпределенные общие параметры. Захват общего параметра позволяет использовать этот параметр в скрытом типе. Это, в свою очередь, влияет на проверку заимствований.
В Rust 2021 и в более ранних изданиях параметры жизни не фиксируются в непрозрачных типах на обнаженных функциях, а также на функциях и методах присущих имплс, если эти параметры времени жизни не упомянуты синтаксически в непрозрачном типе. Например, это ошибка:
//@ edition: 2021
fn f(x: &()) -> impl Sized { x }
error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
--> src/main.rs:1:30
|
1 | fn f(x: &()) -> impl Sized { x }
| --- ---------- ^
| | |
| | opaque type defined here
| hidden type `&()` captures the anonymous lifetime defined here
|
help: add a `use<...>` bound to explicitly capture `'_`
|
1 | fn f(x: &()) -> impl Sized + use<'_> { x }
| +++++++++
С новымuse<..>
Синтаксис, мы можем исправить это, как предложено в ошибке, написав:
fn f(x: &()) -> impl Sized + use<'_> { x }
Ранее правильно исправить этот класс ошибки, требующий определения фиктивной черты, условно вызываемойCaptures
и используя его следующим образом:
trait Captures<T: ?Sized> {}
impl<T: ?Sized, U: ?Sized> Captures<T> for U {}
fn f(x: &()) -> impl Sized + Captures<&'_ ()> { x }
Это было вызвано"Captures
Трюк », и это было немного барокко и тонко. Это больше не нужно.
Был менее правильный, но более удобный способ исправить это, которое часто использовалось"Уловка переживок"Полем Компилятор даже ранее предложил сделать это. Этот трюк выглядел так:
fn f(x: &()) -> impl Sized + '_ { x }
В этом простом случае хитрость точно эквивалентно+ use<'_>
По тонким причинам, объясненным вRFC 3498Полем Тем не менее, в реальных случаях это превышает конструкцию границ возвращаемого непрозрачного типа, что приводит к проблемам. Например, рассмотрим этот код, который вдохновлен реальным случаем в компиляторе ржавчины:
struct Ctx<'cx>(&'cx u8);
fn f<'cx, 'a>(
cx: Ctx<'cx>,
x: &'a u8,
) -> impl Iterator<Item = &'a u8> + 'cx {
core::iter::once_with(move || {
eprintln!("LOG: {}", cx.0);
x
})
//~^ ERROR lifetime may not live long enough
}
Мы не можем удалить+ 'cx
, поскольку срок службы используется в скрытом типе и поэтому должен быть захвачен. Мы также не можем добавить границу'a: 'cx
, поскольку эти жизни на самом деле не связаны, и в целом не будет правдой, что'a
переливы'cx
Полем Если мы напишем+ use<'cx, 'a>
Вместо этого, однако, это будет работать и иметь правильные границы.
Есть некоторые ограничения на то, что мы стабилизируем сегодня. Аuse<..>
Синтаксис в настоящее время не может появиться в пределах признаков или в пределах признаков (но обратите внимание, что там, параметры времени жизни в сфере срока действия уже захватываются по умолчанию), и он должен перечислить все общие типы и параметры в рамках. Мы надеемся поднять эти ограничения с течением времени.
Обратите внимание, что в Rust 2024 приведенные выше примеры будут «просто работать» без необходимостиuse<..>
Синтаксис (или любые уловки). Это связано с тем, что в новом издании непрозрачные типы будут автоматически захватывать все параметры времени жизни в области. Это лучший дефолт, и мы увидели много доказательств того, как это очищает код. В Rust 2024,use<..>
Синтаксис будет служить важным способом отказа от этого дефолта.
Для получения более подробной информации оuse<..>
синтаксис, захват и как это относится к Rust 2024, см."Правила захвата RPIT Lifetime"Глава руководства издания. Для получения подробной информации об общем направлении, см. Наше недавнее сообщение в блоге,"Изменения вimpl Trait
в Rust 2024 ".
Нативный синтаксис для создания необработанного указателя
Небезопасенный код иногда должен иметь дело с указателями, которые могут дать, может быть смещен или не может указывать на действительные данные. Общий случай, когда это возникаетrepr(packed)
структуры. В таком случае важно избегать создания ссылки, так как это вызвало бы неопределенное поведение. Это означает обычное&
и&mut
Операторы не могут быть использованы, так как те, которые создают ссылку - даже если ссылка немедленно приводит к необработанному указателю, уже слишком поздно, чтобы избежать неопределенного поведения.
В течение нескольких лет макросыstd::ptr::addr_of!
иstd::ptr::addr_of_mut!
служили этой цели. Теперь пришло время обеспечить правильный собственный синтаксис для этой операции:addr_of!(expr)
становится&raw const expr
, иaddr_of_mut!(expr)
становится&raw mut expr
Полем Например:
#[repr(packed)]
struct Packed {
not_aligned_field: i32,
}
fn main() {
let p = Packed { not_aligned_field: 1_82 };
// This would be undefined behavior!
// It is rejected by the compiler.
//let ptr = &p.not_aligned_field as *const i32;
// This is the old way of creating a pointer.
let ptr = std::ptr::addr_of!(p.not_aligned_field);
// This is the new way.
let ptr = &raw const p.not_aligned_field;
// Accessing the pointer has not changed.
// Note that `val = *ptr` would be undefined behavior because
// the pointer is not aligned!
let val = unsafe { ptr.read_unaligned() };
}
Нативный синтаксис дает более ясно, что экспрессия операнда этих операторов интерпретируется какРасположение выраженияПолем Это также избегает термина «адресат» при ссылке на действие создания указателя. Указатель естьБольше, чем просто адресТаким образом, ржавчина уходит от таких терминов, как «адрес», которые подтверждают ложную эквивалентность указателей и адресов.
Безопасные предметы сunsafe extern
Код ржавчины может использовать функции и статику из иностранного кода. Типовые подписи этих иностранных предметов представлены вextern
блоки. Исторически все предметы внутриextern
Блоки были небезопасными для использования, но нам не нужно было писатьunsafe
где угодноextern
Блок сам.
Однако, если подпись вextern
Блок неверен, затем использование этого элемента приведет к неопределенному поведению. Это была бы вина человека, который написалextern
Блок или человек, который использовал этот предмет?
Мы решили, что это обязанность человека, пишущегоextern
Блок, чтобы гарантировать, что все подписи, содержащиеся в нем, являются правильными, и поэтому мы теперь разрешаем писатьunsafe extern
:
unsafe extern {
pub safe static TAU: f64;
pub safe fn sqrt(x: f64) -> f64;
pub unsafe fn strlen(p: *const u8) -> usize;
}
Одним из преимуществ этого является то, что элементы вunsafe extern
Блок может быть помечен как безопасное использование. В приведенном выше примере мы можем позвонитьsqrt
или читатьTAU
без использованияunsafe
Полем Предметы, которые не отмечены нимиsafe
илиunsafe
консервативно предполагаетсяunsafe
Полем
В будущих выпусках мы будем поощрять использованиеunsafe extern
с линтами. Начиная с Rust 2024, используяunsafe extern
потребуется.
Для получения дополнительной информации см.RFC 3484и"Небезопасные внешние блоки"Глава руководства издания.
Небезопасные атрибуты
Некоторые атрибуты ржавчины, такие какno_mangle
, может быть использован длявызвать неопределенное поведение без какого -либоunsafe
блокировать. Если бы это был обычный код, мы бы потребовали от их размещения вunsafe {}
Блок, но пока атрибуты не имели сопоставимого синтаксиса. Чтобы отразить тот факт, что эти атрибуты могут подорвать гарантии безопасности Руста, они теперь считаются «небезопасными» и должны быть написаны следующим образом:
#[unsafe(no_mangle)]
pub fn my_global_function() { }
Старая форма атрибута (безunsafe
) в настоящее время все еще принимается, но может быть снят в какой -то момент в будущем, и будет жесткой ошибкой в Rust 2024.
Это влияет на следующие атрибуты:
no_mangle
link_section
export_name
Для получения дополнительной информации см."Небезопасные атрибуты"Глава руководства издания.
Опустив пустые типы в сопоставлении рисунков
Шаблоны, которые соответствуют пустым (a.k.a. необитаемые) типы по значению теперь могут быть опущены:
use std::convert::Infallible;
pub fn unwrap_without_panic<T>(x: Result<T, Infallible>) -> T {
let Ok(x) = x; // the `Err` case does not need to appear
x
}
Это работает с пустыми типами, такими как без вариантаenum Void {}
, или препараты и перечисления с видимым пустым поле#[non_exhaustive]
атрибут. Это также будет особенно полезно в сочетании с типом никогда!
, хотя этот тип все еще нестабилен в это время.
Есть некоторые случаи, когда пустые шаблоны все еще должны быть написаны. По причинам, связанным с неонициализированными значениями и небезопасным кодом, пропущение шаблонов не допускается, если пустой тип доступен через референцию, указатель или полю союза:
pub fn unwrap_ref_without_panic<T>(x: &Result<T, Infallible>) -> &T {
match x {
Ok(x) => x,
// this arm cannot be omitted because of the reference
Err(infallible) => match *infallible {},
}
}
Чтобы не вмешиваться в ящики, которые хотят поддержать несколько версий ржавчины,match
Оружие с пустыми моделями еще не сообщается как предупреждения «недоступного кода», несмотря на то, что их можно удалить.
Семантика NAN с плавающей точкой иconst
Операции на значениях с плавающей точкой (типаf32
иf64
), классно тонкие. Одной из причин этого является существование значений NAN («не число»), которые используются для представления, например, результат0.0 / 0.0
Полем Что делает значения NAN тонкими, так это то, что существует более чем одно из возможных значений NAN. Значение NAN имеет знак (который можно проверить сf.is_sign_positive()
) и полезная нагрузка (которая может быть извлечена с помощьюf.to_bits()
)
Однако как знак, так и полезную нагрузку значений NAN полностью игнорируются==
(который всегда возвращаетсяfalse
) Несмотря на очень успешные усилия по стандартизации поведения операций с плавающей точкой в области аппаратных архитектур, детали того, когда NAN является положительным или отрицательным, и то, что его точная полезная нагрузка отличается в разных архитектурах.
Чтобы сделать вопросы еще более сложными, Rust и его бэкэнд LLVM применяют оптимизации к операциям с плавающей запятой, когда точный числовой результат гарантированно не изменяется, но эти оптимизации могут изменить, что создается значение NAN. Например,f * 1.0
может быть оптимизирован на простоf
Полем Однако, еслиf
это Нэн, это может изменить точный бит -шаблон результата!
С помощью этого выпуска Rust стандартизирует набор правил, как ведут себя значения NAN. Этот набор правилнетполностью детерминированный, что означает, что результат таких операций, как(0.0 / 0.0).is_sign_positive()
может отличаться в зависимости от аппаратной архитектуры, уровней оптимизации и окружающего кода. Код, который направлен на то, чтобы быть полностью переносимым, должен избежать использованияto_bits
и должен использоватьf.signum() == 1.0
вместоf.is_sign_positive()
Полем
Тем не менее, правила тщательно выбираются, чтобы все еще разрешать расширенные методы представления данных, такие как NAN Boxing, быть реализованным в коде Rust. Для получения более подробной информации о том, каковы точные правила, проверьте нашидокументацияПолем
С учетом того, что семантика для значений NAN этот выпуск также позволяет использовать операции с плавающей точкой вconst fn
Полем По причинам, описанным выше, такие операции, как(0.0 / 0.0).is_sign_positive()
(который будет постоянным в Rust 1,83) может привести к другому результату при выполнении во время компиляции по сравнению с временем выполнения. Это не ошибка, и код не должен полагаться наconst fn
Всегда производит тот же результат.
Константы как сразу же
Аconst
Ассамблея операнда теперь предоставляет способ использовать целые числа в качестве немедленных, не храня их в регистре. В качестве примера мы реализуем Syscall дляwrite
вручную:
const WRITE_SYSCALL: c_int = 0x01; // syscall 1 is `write`
const STDOUT_HANDLE: c_int = 0x01; // `stdout` has file handle 1
const MSG: &str = "Hello, world!\n";
let written: usize;
// Signature: `ssize_t write(int fd, const void buf[], size_t count)`
unsafe {
core::arch::asm!(
"mov rax, {SYSCALL} // rax holds the syscall number",
"mov rdi, {OUTPUT} // rdi is `fd` (first argument)",
"mov rdx, {LEN} // rdx is `count` (third argument)",
"syscall // invoke the syscall",
"mov {written}, rax // save the return value",
SYSCALL = const WRITE_SYSCALL,
OUTPUT = const STDOUT_HANDLE,
LEN = const MSG.len(),
in("rsi") MSG.as_ptr(), // rsi is `buf *` (second argument)
written = out(reg) written,
);
}
assert_eq!(written, MSG.len());
Выход:
Hello, world!
Ссылка на игровой площадкеПолем
В вышеперечисленном утверждение, такое какLEN = const MSG.len()
заполняет спецификатор форматаLEN
с непосредственным, который берет ценностьMSG.len()
Полем Это можно увидеть в сгенерированной сборке (значение14
):
lea rsi, [rip + .L__unnamed_3]
mov rax, 1 # rax holds the syscall number
mov rdi, 1 # rdi is `fd` (first argument)
mov rdx, 14 # rdx is `count` (third argument)
syscall # invoke the syscall
mov rax, rax # save the return value
ВидетьСсылкаДля получения более подробной информации.
Безопасно обращаться к небезопасностиstatic
с
Этот код теперь разрешен:
static mut STATIC_MUT: Type = Type::new();
extern "C" {
static EXTERN_STATIC: Type;
}
fn main() {
let static_mut_ptr = &raw mut STATIC_MUT;
let extern_static_ptr = &raw const EXTERN_STATIC;
}
В контексте выражения,STATIC_MUT
иEXTERN_STATIC
являютсяПоместите выраженияПолем Раньше проверяющие безопасность компилятора не знали, что оператор необработанного рефлекса на самом деле не влиял на место операнда, рассматривая его как возможное чтение или запись указателю. Однако на самом деле нет недоступности, так как это просто создает указатель.
Расслабление это может вызвать проблемы, когда некоторые небезопасные блоки теперь сообщаются как неиспользованные, если вы отрицаетеunused_unsafe
Линт, но теперь они полезны только для старых версий. Аннотировать эти небезопасные блоки#[allow(unused_unsafe)]
Если вы хотите поддержать несколько версий ржавчины, как в этом примере Diff:
static mut STATIC_MUT: Type = Type::new();
fn main() {
+ #[allow(unused_unsafe)]
let static_mut_ptr = unsafe { std::ptr::addr_of_mut!(STATIC_MUT) };
}
Ожидается, что будущая версия Rust будет обобщать это на другие выражения, которые будут безопасны в этой позиции, а не только статике.
Стабилизированные API
std::thread::Builder::spawn_unchecked
std::str::CharIndices::offset
std::option::Option::is_none_or
[T]::is_sorted
[T]::is_sorted_by
[T]::is_sorted_by_key
Iterator::is_sorted
Iterator::is_sorted_by
Iterator::is_sorted_by_key
std::future::Ready::into_inner
std::iter::repeat_n
impl<T: Clone> DoubleEndedIterator for Take<Repeat<T>>
impl<T: Clone> ExactSizeIterator for Take<Repeat<T>>
impl<T: Clone> ExactSizeIterator for Take<RepeatWith<T>>
impl Default for std::collections::binary_heap::Iter
impl Default for std::collections::btree_map::RangeMut
impl Default for std::collections::btree_map::ValuesMut
impl Default for std::collections::vec_deque::Iter
impl Default for std::collections::vec_deque::IterMut
Rc<T>::new_uninit
Rc<MaybeUninit<T>>::assume_init
Rc<[T]>::new_uninit_slice
Rc<[MaybeUninit<T>]>::assume_init
Arc<T>::new_uninit
Arc<MaybeUninit<T>>::assume_init
Arc<[T]>::new_uninit_slice
Arc<[MaybeUninit<T>]>::assume_init
Box<T>::new_uninit
Box<MaybeUninit<T>>::assume_init
Box<[T]>::new_uninit_slice
Box<[MaybeUninit<T>]>::assume_init
core::arch::x86_64::_bextri_u64
core::arch::x86_64::_bextri_u32
core::arch::x86::_mm_broadcastsi128_si256
core::arch::x86::_mm256_stream_load_si256
core::arch::x86::_tzcnt_u16
core::arch::x86::_mm_extracti_si64
core::arch::x86::_mm_inserti_si64
core::arch::x86::_mm_storeu_si16
core::arch::x86::_mm_storeu_si32
core::arch::x86::_mm_storeu_si64
core::arch::x86::_mm_loadu_si16
core::arch::x86::_mm_loadu_si32
core::arch::wasm32::u8x16_relaxed_swizzle
core::arch::wasm32::i8x16_relaxed_swizzle
core::arch::wasm32::i32x4_relaxed_trunc_f32x4
core::arch::wasm32::u32x4_relaxed_trunc_f32x4
core::arch::wasm32::i32x4_relaxed_trunc_f64x2_zero
core::arch::wasm32::u32x4_relaxed_trunc_f64x2_zero
core::arch::wasm32::f32x4_relaxed_madd
core::arch::wasm32::f32x4_relaxed_nmadd
core::arch::wasm32::f64x2_relaxed_madd
core::arch::wasm32::f64x2_relaxed_nmadd
core::arch::wasm32::i8x16_relaxed_laneselect
core::arch::wasm32::u8x16_relaxed_laneselect
core::arch::wasm32::i16x8_relaxed_laneselect
core::arch::wasm32::u16x8_relaxed_laneselect
core::arch::wasm32::i32x4_relaxed_laneselect
core::arch::wasm32::u32x4_relaxed_laneselect
core::arch::wasm32::i64x2_relaxed_laneselect
core::arch::wasm32::u64x2_relaxed_laneselect
core::arch::wasm32::f32x4_relaxed_min
core::arch::wasm32::f32x4_relaxed_max
core::arch::wasm32::f64x2_relaxed_min
core::arch::wasm32::f64x2_relaxed_max
core::arch::wasm32::i16x8_relaxed_q15mulr
core::arch::wasm32::u16x8_relaxed_q15mulr
core::arch::wasm32::i16x8_relaxed_dot_i8x16_i7x16
core::arch::wasm32::u16x8_relaxed_dot_i8x16_i7x16
core::arch::wasm32::i32x4_relaxed_dot_i8x16_i7x16_add
core::arch::wasm32::u32x4_relaxed_dot_i8x16_i7x16_add
Эти API теперь стабильны в контексте:
std::task::Waker::from_raw
std::task::Context::from_waker
std::task::Context::waker
$integer::from_str_radix
std::num::ParseIntError::kind
Другие изменения
Проверьте все, что изменилось вРжавчинаВГруз, иКлиппиПолем
Авторы 1,82,0
Многие люди собрались вместе, чтобы создать ржавчину 1.82.0. Мы не могли бы сделать это без всех вас.Спасибо!
Команда релиза ржавчины
Также опубликованоздесь
ФотоМилад ФакурианнаНеспособный
Оригинал