Rust 团队很高兴宣布 Rust 的新版本 1.78.0。Rust 是一种编程语言,它赋予每个人构建可靠高效软件的能力。
如果您通过 rustup
安装了以前的 Rust 版本,您可以使用以下命令获取 1.78.0
$ rustup update stable
如果您还没有,您可以从我们网站上的相应页面 获取 rustup
,并查看 1.78.0 的详细发布说明。
如果您想通过测试未来的版本来帮助我们,您可以考虑在本地更新以使用 beta 通道 (rustup default beta
) 或 nightly 通道 (rustup default nightly
)。请 报告 您遇到的任何错误!
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 {}
有关更多信息,请参阅关于 diagnostic
工具属性命名空间 的参考部分。
unsafe
前提条件
断言 Rust 标准库有许多断言用于 unsafe
函数的前提条件,但历史上它们只在标准库的 #[cfg(debug_assertions)]
构建中启用,以避免影响发布性能。但是,由于标准库通常以发布模式编译和分发,大多数 Rust 开发人员根本没有执行这些检查。
现在,这些断言的条件被延迟到代码生成,因此它们将根据用户自己的调试断言设置进行检查——在调试和测试构建中默认启用。此更改有助于用户在他们的代码中捕获未定义的行为,尽管检查的具体细节通常是不稳定的。
例如,slice::from_raw_parts
需要一个对齐的非空指针。以下使用故意不对齐的指针的行为未定义,虽然如果你运气不好,它可能在过去看起来“有效”,但调试断言现在可以捕获它
fn main() {
let slice: &[u8] = &[1, 2, 3, 4, 5];
let ptr = slice.as_ptr();
// Create an offset from `ptr` that will always be one off from `u16`'s correct alignment
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
- 接受几个
std::error::Error
相关实现的非'static
生命周期 - 使
impl<Fd: AsFd>
impl 接受?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 版,完成了针对 x86-32 和 x86-64 目标的
u128
/i128
ABI 更改 的宣布。使用比 18 版更旧的 LLVM 的发行版可能仍然会遇到该帖子中提到的调用约定错误。
其他更改
查看 Rust、Cargo 和 Clippy 中发生的所有更改。
1.78.0 的贡献者
许多人共同创建了 Rust 1.78.0。没有你们,我们不可能做到。 感谢!