宣布 Rust 1.35.0

2019 年 5 月 23 日 · Rust 发布团队

Rust 团队很高兴宣布 Rust 的新版本 1.35.0。Rust 是一种编程语言,它使每个人都能构建可靠高效的软件。

如果您之前通过 rustup 安装了 Rust,获取 Rust 1.35.0 就像

$ rustup update stable

如果您还没有,您可以从我们网站上的相应页面获取 rustup,并查看 GitHub 上1.35.0 的详细发布说明

1.35.0 稳定版中的内容

此版本的亮点是为 Box<dyn FnOnce>Box<dyn FnMut>Box<dyn Fn> 分别实现了 FnOnceFnMutFn 闭包特征。此外,闭包现在可以强制转换为不安全的函数指针。在Rust 1.32.0 中引入的 dbg! 宏现在也可以在没有参数的情况下调用。此外,标准库还进行了许多稳定化。继续阅读以了解一些亮点,或查看详细的发布说明以获取更多信息。

Box<dyn Fn*> 实现 Fn* 闭包特征

在 Rust 1.35.0 中,FnOnceFnMutFn 特征现在分别为 Box<dyn FnOnce>Box<dyn FnMut>Box<dyn Fn> 实现

以前,如果您想调用存储在已装箱闭包中的函数,您必须使用FnBox。这是因为 Box<dyn FnOnce> 及其同类实例没有实现相应的 Fn* 特征。这也意味着无法将已装箱函数传递给期望 Fn 特征实现者的代码,并且您必须创建临时闭包才能将它们传递下去。

这最终是由于编译器在推理此类实现方面的局限性,该局限性已随着未定大小局部变量的引入而得到解决。

通过此版本,您现在可以在期望实现函数特征的项目的地方使用已装箱函数。

以下代码现在可以工作

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!()

为了所有偶尔和频繁的“打印调试器”的利益,Rust 1.32.0 看到了dbg!的发布。回顾一下,该宏允许您快速检查某些表达式的值及其上下文。例如,在运行

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 已添加到浮点基本类型f32f64

顾名思义,您可以使用它们将一个数字的符号复制到另一个数字上。例如

fn main() {
    assert_eq!(3.5_f32.copysign(-0.42), -3.5);
}

检查 Range 是否包含某个值

Rust 1.35.0 包含 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,我们引入了

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 几乎总是错误的,因为它排除了诸如 u8 之类的类型,这些类型具有微不足道的 drop-glues。此外,T: Drop 不会考虑诸如 String 之类的类型,这些类型没有直接的有趣析构函数行为,而是由于嵌入诸如 Vec<u8> 之类的类型而导致的,这些类型确实具有有趣行为。

除了drop_bounds 之外,此版本的 Clippy 拆分了 lint redundant_closureredundant_closureredundant_closure_for_method_calls

有关更多详细信息,请查看Clippy 的详细发布说明

Cargo 中的更改

有关更多详细信息,请查看Cargo 的详细发布说明

1.35.0 的贡献者

许多人共同创建了 Rust 1.35.0。没有你们,我们不可能做到。 谢谢!