Rust 团队很高兴地宣布 Rust 新版本 1.35.0 发布。Rust 是一种编程语言,旨在帮助所有人构建可靠且高效的软件。
如果你之前通过 rustup 安装了 Rust,那么升级到 Rust 1.35.0 非常简单,只需运行:
$ rustup update stable
如果你还没有安装,你可以从我们的网站上的相应页面 获取 rustup
,并查看 GitHub 上 1.35.0 版本的详细发布说明。
1.35.0 稳定版的新特性
此版本最值得关注的亮点是 FnOnce
、FnMut
和 Fn
闭包 trait 分别为 Box<dyn FnOnce>
、Box<dyn FnMut>
和 Box<dyn Fn>
的实现。此外,闭包现在可以强制转换为 unsafe 函数指针。在 Rust 1.32.0 中引入的 dbg!
macro 现在也可以在不带参数的情况下调用。此外,还有许多标准库稳定化。请继续阅读以了解一些重点,或查看详细发布说明以获取更多信息。
Box<dyn Fn*>
实现 Fn* 闭包 trait
为 在 Rust 1.35.0 中,FnOnce、FnMut 和 Fn trait 现在已为 Box<dyn FnOnce>
、Box<dyn FnMut>
和 Box<dyn Fn>
实现。
之前,如果你想调用存储在 boxed closure 中的函数,你必须使用 FnBox
。这是因为 Box<dyn FnOnce>
及其同类实例没有实现相应的 Fn*
trait。这也意味着不可能将 boxed functions 传递给期望 Fn
trait 实现者的代码,你必须创建临时闭包来向下传递它们。
这最终是由于编译器在推理此类实现方面的限制所致,这个问题已通过引入 unsized locals 得到修复。
在此版本中,你现在可以在需要实现函数 trait 的地方使用 boxed functions。
以下代码现在可以正常工作:
fn foo(x: Box<dyn Fn(u8) -> u8>) -> Vec<u8> {
vec![1, 2, 3, 4].into_iter().map(x).collect()
}
此外,你现在可以直接调用 Box<dyn FnOnce>
对象:
fn foo(x: Box<dyn FnOnce()>) {
x()
}
unsafe fn
指针
将闭包强制转换为 自 Rust 1.19.0 以来,可以将不从环境中捕获的闭包强制转换为函数指针。例如,你可以这样写:
fn twice(x: u8, f: fn(u8) -> u8) -> u8 {
f(f(x))
}
fn main() {
assert_eq!(42, twice(0, |x| x + 21));
}
然而,这尚未扩展到 unsafe 函数指针。在此 Rust 版本中,你现在可以这样做。例如:
/// The safety invariants are those of the `unsafe fn` pointer passed.
unsafe fn call_unsafe_fn_ptr(f: unsafe fn()) {
f()
}
fn main() {
// SAFETY: There are no invariants.
// The closure is statically prevented from doing unsafe things.
unsafe {
call_unsafe_fn_ptr(|| {
dbg!();
});
}
}
dbg!()
不带参数调用 为了所有偶尔和频繁使用 "print debugger" 的人,Rust 1.32.0 发布了 dbg!
macro。回顾一下,这个 macro 允许你快速检查某些表达式的值及其上下文。例如,当运行:
fn main() {
let mut x = 0;
if dbg!(x == 1) {
x += 1;
}
dbg!(x);
}
...你将看到:
[src/main.rs:4] x == 1 = false
[src/main.rs:8] x = 0
如前一节所示,在调用高阶函数 call_unsafe_fn_ptr
的情况下,你现在也可以在不传递任何参数的情况下调用 dbg!
。这在追踪应用程序的分支时非常有用。例如,使用:
fn main() {
let condition = true;
if condition {
dbg!();
}
}
...你将看到:
[src/main.rs:5]
标准库稳定化
在 1.35.0 版本中,许多 API 已变为稳定版。
此外,还添加了一些实现,并发生了一些其他更改。有关更多详细信息,请参阅 详细发布说明。
将一个浮点数的符号复制到另一个
在此版本中,新的方法 copysign
已添加到浮点原始类型 f32
和 f64
。
顾名思义,你可以使用这些方法将一个数字的符号复制到另一个数字。例如:
fn main() {
assert_eq!(3.5_f32.copysign(-0.42), -3.5);
}
Range
是否包含某个值
检查 Rust 1.35.0 在 Range
类型中包含了一些新方法:
Range::contains
RangeFrom::contains
RangeTo::contains
RangeInclusive::contains
RangeToInclusive::contains
使用这些方法,你可以轻松检查给定值是否存在于某个 Range 中。例如,你可以这样写:
fn main() {
if (0..=10).contains(&5) {
println!("Five is included in zero to ten.");
}
}
RefCell
值为两个部分
映射和拆分借用的 在 Rust 1.35.0 中,你现在可以将 RefCell
的借用值映射和拆分为对借用数据不同组件的多个借用。
RefCell
的值
通过闭包替换 此版本在 RefCell
上引入了一个方便的方法 replace_with
。
使用它,你可以更符合人体工程学地映射和替换单元格的当前值,并将旧值作为结果返回。
通过地址而不是值哈希指针或引用
在此版本中,我们引入了:
此函数接受一个原始指针并对其进行哈希。使用 ptr::hash
,你可以避免哈希引用的指向的值,而是哈希地址。
Option<&T>
的内容
复制 从 Rust 1.0.0 的最初版本开始,Option<&T>
和 Option<&mut T>
的方法 Option::cloned
允许你在 Some(_)
的情况下克隆内容。然而,克隆有时可能是一个昂贵的操作,并且方法 opt.cloned()
没有提供任何暗示。
在此 Rust 版本中,我们引入了:
Option::copied
,适用于Option<&T>
和Option<&mut T>
。
opt.copied()
的功能与 opt.cloned()
相同。但是,调用此方法要求 T: Copy
。使用此方法,你可以确保当 T
不再实现 Copy
时代码停止编译。
Clippy 的更改
在此 Rust 版本中,Clippy(一个用于捕获常见错误并改进 Rust 代码的 lint 集合)添加了一个新的 lint drop_bounds
。当你向泛型函数添加 T: Drop
约束时,此 lint 会触发。例如:
fn foo<T: Drop>(x: T) {}
具有 T: Drop
约束几乎总是一个错误,因为它排除了具有 trivial drop-glues 的类型,例如 u8
。此外,T: Drop
没有考虑像 String
这样的类型,它们本身没有有趣的析构函数行为,而是由于嵌入了诸如 Vec<u8>
之类的类型而产生的。
除了 drop_bounds
之外,此版本的 Clippy 将 redundant_closure
lint 拆分为 redundant_closure
和 redundant_closure_for_method_calls
。
有关更多详细信息,请参阅 Clippy 的详细发布说明。
Cargo 的更改
有关更多详细信息,请参阅 Cargo 的详细发布说明。
1.35.0 版本的贡献者
许多人共同努力创建了 Rust 1.35.0。没有你们大家,我们不可能做到。谢谢!