Rust 资讯:新版本 1.78.0 发布
2024 年 5 月 2 日 · Rust 发布团队
Rust 团队很高兴地宣布 Rust 的新版本 1.78.0。Rust 是一种编程语言,它正在帮助每个人构建可靠且高效的软件。
如果你已经通过 rustup 安装了 Rust 的先前版本,你可以通过以下命令获取 1.78.0:
$ rustup update stable
如果你还没有安装 Rust,可以从我们网站的相应页面获取 rustup,并查看 1.78.0 的详细发行说明。
如果你想帮助我们测试未来的版本,你可以考虑本地更新到 beta 频道(rustup default beta
)或 nightly 频道(rustup default nightly
)。请报告你可能遇到的任何错误!
Rust 1.78.0 稳定版中的内容
诊断属性
Rust 现在支持一个 #[diagnostic]
属性命名空间来影响编译器错误消息。这些被视为提示,编译器不一定需要使用它们,提供编译器无法识别的诊断也不会导致错误。这种灵活性允许源代码提供诊断,即使这些诊断不被所有编译器支持,无论这些编译器是不同版本还是完全不同的实现。
随着这个命名空间,支持的第一个属性是 #[diagnostic::on_unimplemented]
,它可以放在一个 trait 上,以自定义当该 trait 被要求但未在类型上实现时的消息。考虑在稳定请求中给出的示例:
#[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
对于 trait 作者,如果你能提供比仅仅讨论缺少的实现更好的提示,这种诊断会更有用。例如,这是标准库中的一个简化示例:
#[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 {}
有关更多信息,请参阅诊断工具属性命名空间的参考部分。
断言不安全前提条件
Rust 标准库对不安全函数的前提条件有许多断言,但历史上这些断言只在 #[cfg(debug_assertions)]
构建的标准库中启用,以避免影响发布性能。然而,由于标准库通常以发布模式编译和分发,大多数 Rust 开发者几乎不会执行这些检查。
现在,这些断言的条件被推迟到代码生成,因此它们会根据用户自己的调试断言设置进行检查——默认情况下在调试和测试构建中启用。这个更改有助于用户捕捉代码中的未定义行为,尽管具体检查的细节通常不是稳定的。
例如,slice::from_raw_parts
需要一个对齐的非空指针。以下使用故意未对齐的指针的例子有未定义行为,虽然如果你运气不好,过去它可能看起来“工作正常”,但现在调试断言可以捕捉到它:
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.
确定性的重新对齐
标准库有一些更改指针和切片对齐的函数,但它们之前有一些使其难以在实践中依赖的警告,如果你严格按照它们的文档。这些警告主要是为了防范常量评估,但它们只对非常量使用是稳定的。现在它们承诺根据实际输入具有一致的运行时行为。
pointer::align_offset
计算更改指针到给定对齐所需的偏移量。如果不可能,它返回 usize::MAX
,但之前它被允许总是返回 usize::MAX
,现在这种行为被移除。
slice::align_to
和 slice::align_to_mut
都会将切片转换为对齐的中间切片和剩余的未对齐的头尾切片。这些方法现在承诺返回最大的中间部分,而不是允许实现返回不太优化的结果,如将所有内容返回为头切片。
稳定的 API
impl Read for &Stdin
- 接受多个 std::error::Error 相关实现的非 'static 生命周期
- 使 impl<Fd: AsFd> impl 接受 ?Sized
impl From<TryReserveError> for io::Error
这些 API 现在在常量上下文中是稳定的:
Barrier::new()
兼容性说明
如之前宣布的那样,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,完成了之前宣布的 x86-32 和 x86-64 目标的 u128/i128 ABI 更改。使用其自身 LLVM 版本低于 18 的分发者仍可能面临该帖子中提到的调用约定错误。
其他更改
查看 Rust、Cargo 和 Clippy 中更改的所有内容。
1.78.0 的贡献者
许多人共同努力创造了 Rust 1.78.0。没有你们的帮助,我们无法完成这一切。感谢大家!
变化总结
Rust 1.78.0 引入了新的诊断属性命名空间,使开发者能够更好地定制编译器错误消息。此外,标准库的断言机制也得到了改进,现在会在用户自己的调试设置下进行检查,帮助捕捉未定义行为。
转载自:https://juejin.cn/post/7370925894662242356