Rust 资讯:新版本 1.79.0 发布

原文链接

2024年6月13日 · Rust 发布团队

Rust 团队很高兴宣布 Rust 的新版本 1.79.0。Rust 是一种编程语言,致力于帮助大家构建可靠和高效的软件。

如果你之前通过 rustup 安装了 Rust,可以使用以下命令获取 1.79.0 版本:

bash 复制代码
$ rustup update stable

如果你还没有安装 rustup,可以从我们网站的相关页面获取,并查看 1.79.0 的详细发布说明。

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

1.79.0 稳定版中的内容

内联常量表达式

const { ... } 块现在在表达式位置是稳定的,允许在不需要额外声明(例如定义 const 项或在 trait 上关联常量)的情况下显式进入 const 上下文。

与 const 项(const ITEM: ... = ...)不同,内联常量可以使用作用域内的泛型,并且其类型是推断的,而不是显式写出的,这使得它们特别适用于内联代码片段。例如,以下模式:

rust 复制代码
const EMPTY: Option<Vec<u8>> = None;
let foo = [EMPTY; 100];

现在可以写成这样:

rust 复制代码
let foo = [const { None }; 100];

特别是在泛型上下文中也是如此,之前需要通过冗长的 trait 声明和关联常量:

rust 复制代码
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
    [const { None::<T> }; N]
}

这使得代码更加简洁和易读。

有关详细信息,请参阅参考文档

关联类型位置的边界

Rust 1.79 稳定了关联项边界语法,允许我们在其他边界内的关联类型位置放置边界,即 T: Trait<Assoc: Bounds...>。这避免了只为约束关联类型而提供额外的显式泛型类型的需要。

此功能允许在几个以前无法做到或施加额外、不必要的约束的位置指定边界:

这个改动涉及 Rust 中关联项边界语法的稳定性,使得在某些情况下约束关联类型变得更加简洁和明确。让我们通过分解来解释这个改动的意义、解决的问题,以及举例说明之前和现在的区别。

问题背景

在 Rust 中,trait 可以有关联类型。例如,一个迭代器 trait 可能有一个关联类型 Item,表示迭代器产生的项类型。以前,为了对这些关联类型施加约束,可能需要额外的泛型参数,导致代码冗长且难以阅读。

解决的问题

在 Rust 1.79 之前,如果我们想要对一个 trait 的关联类型施加约束,通常需要在 where 子句中分开写这些约束,或者引入额外的泛型参数。这不仅增加了代码的复杂性,还降低了代码的可读性和可维护性。

现在的改进

Rust 1.79 允许直接在关联类型位置放置边界,使得这些约束更加简洁明了。具体来说,可以在 trait 和 where 子句中直接对关联类型施加约束,而不需要额外的泛型参数。

举例说明

之前的行为

假设我们有一个 trait Trait,它有一个关联类型 Assoc,我们想要对 Assoc 施加一个边界 Bound。在 Rust 1.79 之前,我们需要这样写:

rust 复制代码
trait Trait {
    type Assoc;
}

fn example<T>(t: T)
where
    T: Trait,
    T::Assoc: Bound,
{
    // ...
}

或者在超类中指定边界:

rust 复制代码
trait SuperTrait: Trait {
    // ...
}

trait Trait {
    type Assoc;
}

impl<T> SuperTrait for T
where
    T: Trait,
    T::Assoc: Bound,
{
    // ...
}

现在的行为

在 Rust 1.79 中,我们可以直接在关联类型位置施加边界,使得代码更加简洁:

rust 复制代码
trait Trait {
    type Assoc: Bound;
}

fn example<T>(t: T)
where
    T: Trait,
{
    // ...
}

或者在超类中直接指定边界:

rust 复制代码
trait CopyIterator: Iterator<Item: Copy> {}

更复杂的例子

假设我们有一个嵌套的关联类型结构,在 Rust 1.79 之前,需要分开写多个 where 子句:

rust 复制代码
trait Trait {
    type Assoc;
}

trait Trait2 {
    type Assoc2;
}

trait Combined: Trait
where
    Self::Assoc: Trait2,
    <Self::Assoc as Trait2>::Assoc2: Copy,
{
    // ...
}

在 Rust 1.79 中,可以直接在关联类型位置施加边界:

rust 复制代码
trait Trait {
    type Assoc: Trait2<Assoc2: Copy>;
}

扩展自动临时生命周期延伸

这个改动涉及 Rust 中的临时变量生命周期延伸问题。为了更好地理解,让我们分解一下这个问题,看看改动的意义、解决的问题,以及举例说明之前和现在的区别。

问题背景

在 Rust 中,临时变量(即在表达式中创建的中间值)的生命周期通常只在其创建的表达式中有效。然而,当这些临时变量被引用时(例如通过借用),可能会遇到生命周期过短的问题,导致编译错误。特别是在 ifmatch 语句中,这个问题尤为常见。

解决的问题

之前,临时变量在 ifmatch 语句中的生命周期管理与在块语句 {} 中的行为不一致。这种不一致可能导致临时变量在 ifmatch 语句中被引用时编译失败。通过这个改动,Rust 1.79 使得临时变量在 ifmatch 语句中的生命周期延伸行为与在块语句中的行为一致,解决了这些编译错误问题。

举例说明

之前的行为

在 Rust 1.79 之前,以下代码会导致编译错误:

rust 复制代码
fn temp() -> i32 {
    42
}

let a = if true {
    &temp() // 过去会报错,临时变量 `temp()` 的生命周期在这里结束
} else {
    &temp() // 过去会报错,临时变量 `temp()` 的生命周期在这里结束
};
rust 复制代码
let a = match () {
    _ => {
        &temp() // 过去会报错,临时变量 `temp()` 的生命周期在这里结束
    }
};

现在的行为

在 Rust 1.79 中,这些代码现在可以正常编译,因为临时变量的生命周期被自动延伸:

rust 复制代码
fn temp() -> i32 {
    42
}

let a = if true {
    &temp() // 现在生命周期会延长,可以正常编译
} else {
    &temp() // 现在生命周期会延长,可以正常编译
};
rust 复制代码
let a = match () {
    _ => {
        &temp() // 现在生命周期会延长,可以正常编译
    }
};

解释

这个改动使得 ifmatch 语句中的临时变量在被引用时,其生命周期会自动延长到外部作用域。这种行为与块语句 {} 中的生命周期延伸一致。例如:

rust 复制代码
let a = {
    &temp() // 生命周期会延长,可以正常编译
};

在标准库构建中启用帧指针

由 Rust 项目分发的标准库现在使用 -Cforce-frame-pointers=yes 编译,使下游用户更容易剖析他们的程序。请注意,标准库仍然带有行级调试信息(例如 DWARF),尽管在 Cargo 的发布配置中默认剥离了这些信息。

稳定的 API

{integer}::unchecked_add

{integer}::unchecked_mul

{integer}::unchecked_sub

<[T]>::split_at_unchecked

<[T]>::split_at_mut_unchecked

<[u8]>::utf8_chunks

str::Utf8Chunks

str::Utf8Chunk

<*const T>::is_aligned

<*mut T>::is_aligned

NonNull::is_aligned

<*const [T]>::len

<*mut [T]>::len

<*const [T]>::is_empty

<*mut [T]>::is_empty

NonNull::<[T]>::is_empty

CStr::count_bytes

io::Error::downcast

num::NonZero

path::absolute

proc_macro::Literal::byte_character

proc_macro::Literal::c_string

这些 API 现在在 const 上下文中是稳定的:

Atomic*::into_inner

io::Cursor::new

io::Cursor::get_ref

io::Cursor::position

io::empty

io::repeat

io::sink

panic::Location::caller

panic::Location::file

panic::Location::line

panic::Location::column

其他变化

查看 RustCargoClippy 中所有更改的详细信息。

1.79.0 版本的贡献者 许多人一起创造了 Rust 1.79.0。没有你们,我们无法做到这一点。感谢!

相关推荐
Enaium6 小时前
Rust入门实战 编写Minecraft启动器#3解析资源配置
java·开发语言·rust
爱分享的码瑞哥14 小时前
Rust 进阶教程
开发语言·windows·rust
CCI34414 小时前
Rust简明教程第三章-所有权与借用
开发语言·数据库·rust
影子LEON16 小时前
【Asterinas】Asterinas 进程启动与切换
rust·asterinas
jxandrew21 小时前
通过AIS实现船舶追踪与照射
rust·ais·船舶追踪
__lost1 天前
RUST 编程语言 绘制随机颜色图片 画圆形 画矩形 画直线
开发语言·后端·rust
CCI3441 天前
Rust简明教程第九章-多线程&并发
开发语言·后端·rust
我是前端小学生1 天前
Rust入门系列:15、Rust中的项目、包和模块
rust
CCI3441 天前
Rust简明教程第一章-easy rust
开发语言·后端·rust
与墨学长2 天前
Rust破界:前端革新与Vite重构的深度透视(中)
开发语言·前端·rust·前端框架·wasm