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

相关推荐
暴躁小师兄数据学院12 小时前
【WEB3.0零基础转行笔记】Rust编程篇-第一讲:课程简介
rust·web3·区块链·智能合约
Hello.Reader20 小时前
Rocket Fairings 实战把全局能力做成“结构化中间件”
中间件·rust·rocket
Andrew_Ryan20 小时前
rust arena 内存分配
rust
Andrew_Ryan20 小时前
深入理解 Rust 内存管理:基于 typed_arena 的指针操作实践
rust
微小冷2 天前
Rust异步编程详解
开发语言·rust·async·await·异步编程·tokio
鸿乃江边鸟2 天前
Spark Datafusion Comet 向量化Rust Native--CometShuffleExchangeExec怎么控制读写
大数据·rust·spark·native
明飞19873 天前
tauri
rust
咚为3 天前
Rust tokio:Task ≠ Thread:Tokio 调度模型中的“假并发”与真实代价
开发语言·后端·rust
天天进步20153 天前
Motia性能进阶与未来:从现有源码推测 Rust 重构之路
开发语言·重构·rust
Hello.Reader4 天前
Rocket 0.5 响应体系Responder、流式输出、WebSocket 与 uri! 类型安全 URI
websocket·网络协议·安全·rust·rocket