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

相关推荐
码农飞飞6 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货6 小时前
Rust 的简介
开发语言·后端·rust
qq_172805596 小时前
RUST学习教程-安装教程
开发语言·学习·rust·安装
monkey_meng6 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
新知图书7 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
fqbqrr11 小时前
2411rust,实现特征
rust
码农飞飞12 小时前
详解Rust枚举类型(enum)的用法
开发语言·rust·match·枚举·匹配·内存安全
一个小坑货17 小时前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet2717 小时前
【Rust练习】22.HashMap
开发语言·后端·rust
VertexGeek20 小时前
Rust学习(八):异常处理和宏编程:
学习·算法·rust