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。没有你们,我们无法做到这一点。感谢!

相关推荐
DongLi012 天前
rustlings 学习笔记 -- exercises/05_vecs
rust
番茄灭世神3 天前
Rust学习笔记第2篇
rust·编程语言
shimly1234563 天前
(done) 速通 rustlings(20) 错误处理1 --- 不涉及Traits
rust
shimly1234563 天前
(done) 速通 rustlings(19) Option
rust
@atweiwei3 天前
rust所有权机制详解
开发语言·数据结构·后端·rust·内存·所有权
shimly1234563 天前
(done) 速通 rustlings(24) 错误处理2 --- 涉及Traits
rust
shimly1234563 天前
(done) 速通 rustlings(23) 特性 Traits
rust
shimly1234563 天前
(done) 速通 rustlings(17) 哈希表
rust
shimly1234563 天前
(done) 速通 rustlings(15) 字符串
rust
shimly1234563 天前
(done) 速通 rustlings(22) 泛型
rust