在荷兰乌特勒支举行的Rust 十周年庆祝活动现场,Rust 团队很高兴地宣布 Rust 的新版本 1.87.0 发布了!

今天的发布日恰好是 Rust 1.0 发布十周年的纪念日!

感谢过去和现在为 Rust 做出贡献的无数贡献者。愿 Rust 持续繁荣发展,再迎下一个又一个十年!🎉

像往常一样,新版本包含了过去六周内作为 beta 版本一部分的所有更改,遵循了我们自 Rust 1.0 以来一直遵循的稳定规律的发布周期。

如果您之前通过 rustup 安装了 Rust,您可以通过以下命令获取 1.87.0 版本:

$ rustup update stable

如果您还没有安装 rustup,可以从我们网站上的相应页面获取 rustup,并查阅 1.87.0 的详细发布说明。

如果您想通过测试未来版本来帮助我们,可以考虑在本地更新使用 beta 通道(rustup default beta)或 nightly 通道(rustup default nightly)。请报告您可能遇到的任何错误!

1.87.0 stable 版本中有哪些新内容

匿名管道

1.87 版本将匿名管道的访问权限添加到标准库中。这包括与 std::process::Command 的输入/输出方法的集成。例如,现在将 stdout 和 stderr 流合并为一个相对简单,如下所示,而以前则需要额外的线程或平台特定的函数。

use std::process::Command;

use std::io::Read;

let (mut recv, send) = std::io::pipe()?;

let mut command = Command::new("path/to/bin")

// Both stdout and stderr will write to the same pipe, combining the two.

.stdout(send.try_clone()?)

.stderr(send)

.spawn()?;

let mut output = Vec::new();

recv.read_to_end(&mut output)?;

// It's important that we read from the pipe before the process exits, to avoid

// filling the OS buffers if the program emits too much output.

assert!(command.wait()?.success());

安全的架构内建函数

大多数 std::arch 内建函数之所以不安全只是因为需要启用目标特性,现在在启用了这些特性的安全代码中可以调用它们了。例如,下面这个使用手动内建函数实现数组求和的示例程序,现在可以使用安全代码来实现核心循环了。

#![forbid(unsafe_op_in_unsafe_fn)]

use std::arch::x86_64::*;

fn sum(slice: &[u32]) -> u32 {

#[cfg(target_arch = "x86_64")]

{

if is_x86_feature_detected!("avx2") {

// SAFETY: We have detected the feature is enabled at runtime,

// so it's safe to call this function.

return unsafe { sum_avx2(slice) };

}

}

slice.iter().sum()

}

#[target_feature(enable = "avx2")]

#[cfg(target_arch = "x86_64")]

fn sum_avx2(slice: &[u32]) -> u32 {

// SAFETY: __m256i and u32 have the same validity.

let (prefix, middle, tail) = unsafe { slice.align_to::<__m256i>() };

let mut sum = prefix.iter().sum::();

sum += tail.iter().sum::();

// Core loop is now fully safe code in 1.87, because the intrinsics require

// matching target features (avx2) to the function definition.

let mut base = _mm256_setzero_si256();

for e in middle.iter() {

base = _mm256_add_epi32(base, *e);

}

// SAFETY: __m256i and u32 have the same validity.

let base: [u32; 8] = unsafe { std::mem::transmute(base) };

sum += base.iter().sum::();

sum

}

asm! 跳转到 Rust 代码

内联汇编 (asm!) 现在可以跳转到 Rust 代码中的标签块。这使得更灵活的低级编程成为可能,例如在操作系统内核中实现优化的控制流或更高效地与硬件交互。

asm! 宏现在支持 label 操作数,它充当跳转目标。

标签必须是一个返回类型为 () 或 ! 的块表达式。

当跳转到该块时,该块将执行,然后执行将在 asm! 块之后继续。

在同一个 asm! 调用中使用 output 和 label 操作数仍然是不稳定的。

unsafe {

asm!(

"jmp {}",

label {

println!("Jumped from asm!");

}

);

}

更多详情,请查阅参考资料。

Trait 定义中 impl Trait 的精确捕获 (+ use<...>)

此版本稳定了在 trait 定义中使用 impl Trait 返回类型指定精确捕获的泛型类型和生命周期。这使得该功能可以在 trait 定义中使用,扩展了 1.82 中针对非 trait 函数的稳定化。

一些解糖示例

trait Foo {

fn method<'a>(&'a self) -> impl Sized;

// ... desugars to something like:

type Implicit1<'a>: Sized;

fn method_desugared<'a>(&'a self) -> Self::Implicit1<'a>;

// ... whereas with precise capturing ...

fn precise<'a>(&'a self) -> impl Sized + use;

// ... desugars to something like:

type Implicit2: Sized;

fn precise_desugared<'a>(&'a self) -> Self::Implicit2;

}

稳定的 API

Vec::extract_if

vec::ExtractIf

LinkedList::extract_if

linked_list::ExtractIf

<[T]>::split_off

<[T]>::split_off_mut

<[T]>::split_off_first

<[T]>::split_off_first_mut

<[T]>::split_off_last

<[T]>::split_off_last_mut

String::extend_from_within

os_str::Display

OsString::display

OsStr::display

io::pipe

io::PipeReader

io::PipeWriter

impl From for OwnedHandle

impl From for OwnedHandle

impl From for Stdio

impl From for Stdio

impl From for OwnedFd

impl From for OwnedFd

Box>::write

impl TryFrom> for String

<*const T>::offset_from_unsigned

<*const T>::byte_offset_from_unsigned

<*mut T>::offset_from_unsigned

<*mut T>::byte_offset_from_unsigned

NonNull::offset_from_unsigned

NonNull::byte_offset_from_unsigned

::cast_signed

NonZero::::cast_signed.

::cast_unsigned.

NonZero::::cast_unsigned.

::is_multiple_of

::unbounded_shl

::unbounded_shr

::unbounded_shl

::unbounded_shr

::midpoint

::from_utf8

::from_utf8_mut

::from_utf8_unchecked

::from_utf8_unchecked_mut

这些先前稳定的 API 现在在 const 上下文中也稳定了

core::str::from_utf8_mut

<[T]>::copy_from_slice

SocketAddr::set_ip

SocketAddr::set_port,

SocketAddrV4::set_ip

SocketAddrV4::set_port,

SocketAddrV6::set_ip

SocketAddrV6::set_port

SocketAddrV6::set_flowinfo

SocketAddrV6::set_scope_id

char::is_digit

char::is_whitespace

<[[T; N]]>::as_flattened

<[[T; N]]>::as_flattened_mut

String::into_bytes

String::as_str

String::capacity

String::as_bytes

String::len

String::is_empty

String::as_mut_str

String::as_mut_vec

Vec::as_ptr

Vec::as_slice

Vec::capacity

Vec::len

Vec::is_empty

Vec::as_mut_slice

Vec::as_mut_ptr

移除 i586-pc-windows-msvc 目标平台

二级目标平台 i586-pc-windows-msvc 已被移除。与更流行的 一级目标平台 i686-pc-windows-msvc 相比,i586-pc-windows-msvc 的区别在于它不需要 SSE2 指令支持。但 Windows 10,作为所有 windows 目标平台(除 win7 目标平台外)所需的最低操作系统版本,本身就需要 SSE2 指令。

目前针对 i586-pc-windows-msvc 的所有用户应迁移到 i686-pc-windows-msvc。

您可以查看重大变更提案了解更多信息。

其他变更

查看 Rust、Cargo 和 Clippy 中所有变更的详细信息。

1.87.0 版本的贡献者

许多人齐心协力创建了 Rust 1.87.0。没有大家的贡献,这一切都不可能实现。感谢!