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 中,临时变量(即在表达式中创建的中间值)的生命周期通常只在其创建的表达式中有效。然而,当这些临时变量被引用时(例如通过借用),可能会遇到生命周期过短的问题,导致编译错误。特别是在 if
和 match
语句中,这个问题尤为常见。
解决的问题
之前,临时变量在 if
和 match
语句中的生命周期管理与在块语句 {}
中的行为不一致。这种不一致可能导致临时变量在 if
和 match
语句中被引用时编译失败。通过这个改动,Rust 1.79 使得临时变量在 if
和 match
语句中的生命周期延伸行为与在块语句中的行为一致,解决了这些编译错误问题。
举例说明
之前的行为
在 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() // 现在生命周期会延长,可以正常编译
}
};
解释
这个改动使得 if
和 match
语句中的临时变量在被引用时,其生命周期会自动延长到外部作用域。这种行为与块语句 {}
中的生命周期延伸一致。例如:
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
其他变化
查看 Rust、Cargo 和 Clippy 中所有更改的详细信息。
1.79.0 版本的贡献者 许多人一起创造了 Rust 1.79.0。没有你们,我们无法做到这一点。感谢!