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 稳定版的新特性

此版本最值得关注的亮点是 FnOnceFnMutFn 闭包 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 已添加到浮点原始类型 f32f64

顾名思义,你可以使用这些方法将一个数字的符号复制到另一个数字。例如:

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

检查 Range 是否包含某个值

Rust 1.35.0 在 Range 类型中包含了一些新方法:

使用这些方法,你可以轻松检查给定值是否存在于某个 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 约束几乎总是一个错误,因为它排除了具有 trivial drop-glues 的类型,例如 u8。此外,T: Drop 没有考虑像 String 这样的类型,它们本身没有有趣的析构函数行为,而是由于嵌入了诸如 Vec<u8> 之类的类型而产生的。

除了 drop_bounds 之外,此版本的 Clippy redundant_closure lint 拆分为 redundant_closureredundant_closure_for_method_calls

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

Cargo 的更改

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

1.35.0 版本的贡献者

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