发布 Rust 1.35.0

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

Rust 团队很高兴宣布 Rust 新版本 1.35.0 发布。Rust 是一种编程语言,致力于赋能每个人构建可靠且高效的软件。

如果您之前已经通过 rustup 安装了 Rust,升级到 Rust 1.35.0 只需要运行

$ rustup update stable

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

1.35.0 稳定版本包含什么

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

Box<dyn Fn*> 实现了 Fn* 闭包 trait

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

此前,如果您想调用存储在 boxed closure 中的函数,必须使用 FnBox。这是因为 Box<dyn FnOnce> 等实例没有实现对应的 Fn* trait。这也意味着无法将 boxed 函数传递给期望实现 Fn trait 的代码,您不得不创建临时闭包来传递它们。

这最终是由于编译器在处理此类实现方面的限制所致,随着 unsized locals 的引入,该限制现已得到解决。

通过此版本,您现在可以在期望实现函数 trait 的地方使用 boxed function。

以下代码现在可以工作了

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 已经稳定化。

此外,还增加了一些实现,并发生了其他更改。请查看详细发布说明了解更多细节。

将一个浮点数的符号复制到另一个浮点数上

在此版本中,已向浮点原始类型 f32f64 添加了新的 copysign 方法

正如名称所示,您可以使用这些方法将一个数的符号复制到另一个数上。例如

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-glue 的类型。此外,T: Drop 并未考虑到像 String 这样的类型不直接具有有趣的析构函数行为,而是由于嵌入了具有此类行为的类型(例如 Vec<u8>)而间接具有。

除了 drop_bounds 之外,此版本的 Clippy 还 lintredundant_closure 分割为 redundant_closureredundant_closure_for_method_calls

请查看 Clippy 的详细发布说明了解更多细节。

Cargo 中的变更

请查看 Cargo 的详细发布说明了解更多细节。

1.35.0 的贡献者

许多人共同努力创建了 Rust 1.35.0。没有你们所有人,这是不可能的。感谢!