1.81.0
稳定版
core::error::错误
1.81
稳定了核心
中的Error
特征,允许在#![no_std]
库中使用特征.这样在相同错误
特征上,可标准化
更广泛的Rust
生态系统,而不管库的环境
.
新的排序
实现
都已按新算法
更新了标准库
中的稳定
和不稳定
排序实现,从而改进
了它们的运行时性能和编译时间
.
此外,两个新的排序算法
都试检测Ord
的阻止产生有意义
的排序结果
的错误实现
,且现在此时会恐慌
而不是返回有效随机排列的数据
.
遇见这些恐慌
的用户,应该审计他们的排序
实现,以确保它们满足PartialOrd
和Ord
中记录的要求
.
#[expect(lint)]
1.81
稳定了一个新的期望
的检查
级,它允许显式说明
应有的检查
,否则,则发出警告
.此操作的期望用例
是无论是因为检查
实现错误,还是正在重构
,同时想知道何时不再需要检查
,来临时使检查
静音.
如,如果你正在移动代码基
以符合Clippy
检查(如undocumented_unsafe_blocks
)强制的新限制
,则你可在转换
时使用#[expect(clippy::undocumented_unsafe_blocks)]
,确保一旦记录
了所有不安全的块
,就可选择
拒绝检查
来它.
Clippy
还有两个检查
来强制使用此功能,并帮助移动现有属性
:
1,clippy::allow_attributes
在支持#[expect]
或移动#[allow]
属性到#[expect]
时,限制允许属性
.
2,clippy::allow_attributes_without_reason
要求#[allow]
属性的原因
.
检查原因
更改检查
级一般事出有因.如,如果在不支持浮点
的环境中,运行代码
,你可用Clippy
的#![deny(clippy::float_arithmetic)]
来检查.
但是,如果项的新开发者
看到此检查
触发,他们需要查找(想)拒绝
中解释加它
的原因的评论
.在Rust1.81
中,可直接在编译器消息
中通知他们
:
错误:检测到浮点运算
:
-->src/lib.rs:4:5
|
4|a+b
|^^^^^
|
=帮助:有关更多信息,请访问https://rustlang.github.io/rustclippy/master/index.html#float_arithmetic
=注意:不支持硬件浮点数
注意:在此处定义检查
级
–>src/lib.rs:1:9
|
1|#![deny(clippy::float_arithmetic,reason="不支持硬件浮点数")]
|^^^^^^^^^^^^^^^^^^^^^^^^
稳定的API
core::error
hint::assert_unchecked
fs::exists
AtomicBool::fetch_not
Duration::abs_diff
IoSlice::advance
IoSlice::advance_slices
IoSliceMut::advance
IoSliceMut::advance_slices
PanicHookInfo
PanicInfo::message
PanicMessage
这些API
现在在常
环境中是稳定
的:
char::from_u32_unchecked (function)
char::from_u32_unchecked (method)
CStr::count_bytes
CStr::from_ptr
兼容说明
分割恐慌
勾挂和恐慌
处理器参数
已重命名std::panic::PanicInfo
为std::panic::PanicHookInfo
.继续按别名
使用旧名
,但从Rust1.82.0
开始会导致弃用警告
.
但是,core::panic::PanicInfo
将不变,因为现在这是个不同类型
.
原因是这些类
有不同角色
:std::panic::PanicHookInfo
是std
环境中恐慌
勾挂的参数(恐慌
可有任意负载
),而core::panic::PanicInfo
是在非标准(#![no_std])
环境中#[panic_handler]
的参数(其中恐慌
总是带格式化的消息
).
分离
这些类允许为这些类添加更多有用的方法
,如std::panic::PanicHookInfo::payload_as_str()
和core::panic::PanicInfo::message()
.
在extern"C"
函数中中止未抓的恐慌
这完成了从1.71
开始的期望跨ABI
边界展开时(在其他-展开
变量)添加了特有的"C展开"
的ABI
转换.从1.81
开始,非展开ABI
(如,"C"
)现在会在未抓的展开
时中止
,从而解决长期
的健壮性问题
.
依赖展开的程序
应,转而使用-展开
后缀的ABI
变量.
已更改WASI0.1
目标命名
使用wasm32wasi
目标(以WASI0.1
为目标)现在发出编译器警告
,并要求用户切换
到wasm32wasip1
目标.两个目标
是相同的,只是重命名了wasm32wasi
,更改WASI
目标,是为了在2025
年1月删除wasm32wasi
.
修复CVE-2024-43402
现在,在窗口
上,调用批处理文件
时,如果有窗口
会忽略和去掉的尾空格或句点
,则std::process::Command
可正确转义参数
.
1.82.0
稳定版
货物信息
Cargo
现在有一个信息
子命令来显示
注册表中包的信息
.
如,以下是可见的cargo info cc
:
cc #build-dependencies
版本:1.1.23
(最新1.1.30
)
许可:MIT
或Apache-2.0
Rust
版本:1.63
文档:https://docs.rs/cc
主页:https://github.com/rustlang/ccrs
仓库:https://github.com/rustlang/ccrs
crates.io
:https://crates.io/crates/cc/1.1.23
特征:
作业服务器=[]
并行=[dep:libc,dep:jobserver]
注意:要查看如何依赖CC
,请运行cargo tree --invert --package cc@1.1.23
默认,如果有,cargo-info
描述本地Cargo.lock
中的包版本
.如见,它也会指示何时有更新的版本
,而cargo info cc@1.1.30
会报告它.
促进苹果
64
位ARM
上的macOS
现在是第1层
Mac,Catalyst
目标现在是第2层
精确捕捉使用<..>
语法
Rust
现在支持在某些impl Trait
约束内,用use<..>
语法来控制抓哪些
泛型生命期参数
.
Rust
中的返回位置实现特征(RPIT)
类型抓某些泛型参数
.它允许在隐藏
类型中使用该泛型参数
.这反之又会影响借用检查
.
在Rust2021
及更早版本
中,除非在暗类型
中按语法形式
提及这些生命期参数
,否则不会在裸函数
和固有实现
的函数和方法
上按暗类型
抓生命期参数
.
如,这是个错误
:
//@版本`:2021`
fn f(x: &()) -> impl Sized { x }
有了新的use<..>
语法,可按错误
中的建议解决它
,方法是写:
fn f(x: &()) -> impl Sized + use<'_> { x }
以前,正确
修复此类错误
需要定义一个虚特征
(一般叫抓
),并如下使用它
:
trait Captures<T: ?Sized> {}
impl<T: ?Sized, U: ?Sized> Captures<T> for U {}fn f(x: &()) -> impl Sized + Captures<&'_ ()> { x }
现在不再需要它
.
有个经常使用的叫"超期技巧
"的不太正确但更方便
的方法来解决它
.编译器甚至之前建议这样做
.该技巧如下
:
fn f(x: &()) -> impl Sized + '_ { x }
在此简单用例时,如在RFC3498
中解释,该技巧
完全等价于+use<'_>
.但是,实际情况下,这会过度约束
返回的暗
类型的约束,从而导致问题
.
如,考虑以下Rust
编译器中真实案例
的代码
:
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})//~^错误,生命期可能不够长
}
无法删除+'cx
,因为在隐藏
类型中用生命期
,因此必须抓它.也不能添加'a:'cx
约束,因为这些生命期
实际上无关
,且一般'a
不一定比'cx
活得更久
.
但是,如果写成+use<'cx,'a>
,这工作
并有正确的约束
.
今天稳定
的东西还有一些限制
.用<..>
语法当前不能出现在特征
或特征实现
中(但注意,默认
已抓了域内
的生命期参数
),且它必须列举
所有域内
的泛型类型
和常
参数.期望未来
会取消这些限制
.
注意,在Rust2024
中,上述示例无需用用<..>
语法(或技巧)就"正常"
工作.这是因为在新版本
中,暗类型
自动抓域内
的所有生命期参数
.
这是个更好的默认值
.在Rust2024
中,用<..>
语法是选出
该默认值的重要方式
.
创建原始指针
的本地语法
不安全代码
有时必须处理可能挂起,可能未对齐或可能指向无效数据
的指针
.此常见情况
是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 };//这是未定义行为!编译器拒绝它.`let ptr=&p.not_aligned_fieldas*const i32;`这是创建指针的旧方法.let ptr = std::ptr::addr_of!(p.not_aligned_field);//这就是新的方式.let ptr = &raw const p.not_aligned_field;//访问指针不变.注意,因为指针未对齐,`'val=*ptr'`是未定义行为!let val = unsafe { ptr.read_unaligned() };
}
本地语法
更清楚地表明,按位置
式解释这些符号的操作数式
.还避免了在创建指针
时使用"的地址"
术语.
指针
不仅是个地址
,因此Rust
正在摆脱像重申了指针
和地址
的错误等价性
的"的地址"
此术语.
带不安全外
的安全对象
Rust
代码可用外部代码
的函数和静态数据
.在外
块中提供,这些外部项
的类型签名
.历史上,外
块中的所有项
用起来都是不安全的
,但不必在外
块自身
编写不安全
.
但是,如果外
块中的签名
错误,则使用该项
会导致未定义行为
.那是写外
块的人的错,还是用该项
的人的错?
已决定编写外
块的人,负责确保
其中包含的所有签名
都是正确
的,因此现在允许编写
不安全的外
:
unsafe extern {pub safe static TAU: f64;pub safe fn sqrt(x: f64) -> f64;pub unsafe fn strlen(p: *const u8) -> usize;
}
一个好处
是,可按安全使用
标记不安全的外
块中的项.在上例中,可无需使用不安全
,就调用sqrt
或读取TAU
.
按不安全
保守假设无安全
或不安全
标记的项.
在未来发布中,鼓励与检查
一起,使用不安全
的外
.从Rust2024
开始,会要求不安全 外
.
不安全属性
一些Rust
属性,如no_mangle
,可用来在没有不安全
块时,导致未定义
行为.如果这是普通代码
,会要求在不安全的{}
块中放置它们
,但当前,属性
还没有类似的语法
.
为了反映这些属性
可能会破坏Rust
的安全保证,它们现在是"不安全的
",应该如下写
:
#[unsafe(no_mangle)]
pub fn my_global_function() { }
当前仍接受该属性的旧形式
(没有不安全
),但可能会在未来
反对它,且在Rust2024
中将是个硬性错误
.
这会影响以下属性
:
no_mangle
link_section
export_name
在匹配模式中省略空类型
现在可以省略按值匹配空
(又名无人区
)类型的模式
:
use std::convert::Infallible;
pub fn unwrap_without_panic<T>(x: Result<T, Infallible>) -> T {let Ok(x) = x; //`'Err'`情况不需要出现x
}
这适合空类型
,如无变量
的枚举 Void{}
,或带可见空字段
且无#[non_exhaustive]
属性的结构和枚举
.它与尽管当前仍不稳定的永不!
类型结合使用
时也特别有用
.
有时,必须写空模式
.因为未初化值和不安全代码
,如果通过引用,指针或联字段
访问空类型
,则禁止省略模式
:
pub fn unwrap_ref_without_panic<T>(x: &Result<T, Infallible>) -> &T {match x {Ok(x) => x,//因为引用,不能省略此分支Err(infallible) => match *infallible {},}
}
为了避免干扰想支持多个Rust
版本的箱
,有空模式的匹配项
,尽管可删除它们
,但尚未按"不可达"
警告报告.
浮点非数
语义和常
对(f32
和f64
类型)浮点值的运算,是出了名的微妙
.原因之一是有用来表示0.0/0.0
的结果的NaN(非数)
值.
非数
值之所以微妙
,是因为有多个可能
的非数
值.非数
值有一个(可用f.is_sign_positive()
检查)符号
和一个(可用f.to_bits()
提取的)负载
.
但是,==
完全忽略非数值
的符号和负载
(总是返回假
).尽管在跨硬件架构标准化浮点运算的行为
方面非常成功
,但非数
何时为正或负
及其确切负载的细节
因架构
而异.
更复杂的是,当保证精确
的数字结果
不变时,Rust
及其LLVM
后端优化浮点运算
,但这些优化
可改变生成的非数值
.
如,f*1.0
可优化为仅f
.但是,如果f
是非数
,则会改变结果的确切位模式
!
在该版本中,标准化了Rust
对非数
值的行为方式的一组规则
.它不是完全确定性
的,即(0.0/0.0).is_sign_positive()
等操作的结果可能会因硬件架构,优化级和周围代码
而异.
为了可移植
,代码应避免使用to_bits
,且应使用f.signum()==1.0
而不是f.is_sign_positive()
.
但是,精心选择这些规则
,仍允许在Rust
代码中实现高级数据
表示技术,如非数
装箱.
更多细节,见文档.
确定非数
值的语义后,该版本还允许在const fn
中使用浮点运算
.
因此,像(0.0/0.0).is_sign_positive()
此操作(在Rust1.83
中是常稳定
)在编译时和运行时
时可能会产生不同结果
.这不是漏洞
,代码不能依赖总是产生完全相同结果
的const fn
.
作为汇编立即数
的常数
常
汇编操作数,现在无需先在寄存器
中保存它们
,而按立即数
用整数.如,实现一个syscall
手动写
:
const WRITE_SYSCALL: c_int = 0x01; //`syscall1`是`'写'`,
const STDOUT_HANDLE: c_int = 0x01; //`'stdout'`有文件句柄1
const MSG: &str = "Hello, world!\n";
let written: usize;
//签名:`ssize_t write(int fd, const void buf[], size_t count)`
unsafe {core::arch::asm!("mov rax, {SYSCALL} "//`rax`保存系统调用号,"mov rdi, {OUTPUT} " //`"rdi`为`"fd"`(第一个参数)","mov rdx, {LEN} " //`rdx`为`"count"`(第三个参数)","syscall " //调用`syscall`","mov {written}, rax "//保存返回值",SYSCALL = const WRITE_SYSCALL,OUTPUT = const STDOUT_HANDLE,LEN = const MSG.len(),in("rsi") MSG.as_ptr(), //`rsi`是`'buf*'`(第二个参数)written = out(reg) written,);
}
assert_eq!(written, MSG.len());
输出:
世界你好!
玩耍地方
链接.
上面代码中,如LEN=const MSG.len()
之类的语句
使用带MSG.len()
值的立即数
填充LEN
格式限定符.可在生成的汇编
中看到(值为14
):
lea rsi, [rip + .L__unnamed_3]
mov rax, 1 //`rax`保存系统调用号,
mov rdi, 1 //`"rdi`为`"fd"`(第一个参数)",
mov rdx, 14 //`rdx`为`"count"`(第三个参数)",
syscall //调用`syscall`"
mov rax, rax //"保存返回值"
更多细节,见引用.
安全地处理不安全的静态数据
现在允许以下代码
:
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
检查,现在会按未使用报告
一些不安全的块
,但现在仅在旧版本上用它们.
如果想支持多个版本
的Rust
,与该示例一样,请用#[allow(unused_unsafe)]
注解这些不安全的块
:
static mut STATIC_MUT: Type = Type::new();fn main() {
+ #[allow(unused_unsafe)]let static_mut_ptr = unsafe { std::ptr::addr_of_mut!(STATIC_MUT) };}
稳定的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<T>::assume_init
Rc<[T]>::new_uninit_slice
Rc<[MaybeUninit<T>]>::assume_init
Arc<T>::new_uninit
Arc<T>::assume_init
Arc<[T]>::new_uninit_slice
Arc<[MaybeUninit<T>]>::assume_init
Box<T>::new_uninit
Box<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