Rust 1.34.0 发布

2019年4月11日 · Rust 发布团队

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

如果您之前通过 rustup 安装了 Rust 版本,那么获取 Rust 1.34.0 就如同运行以下命令一样简单:

$ rustup update stable

如果您还没有安装 rustup,您可以从我们网站上的相应页面获取 rustup

1.34.0 稳定版的新特性

此版本中最大的特性是引入了备用 cargo 注册表。该版本还包括对文档测试中 ? 的支持、对 #[attribute(..)] 的一些改进以及 TryFrom 的稳定化。请继续阅读以了解一些亮点,或查看详细的发行说明以获取更多信息。

备用 cargo 注册表

自 1.0 之前,Rust 就拥有一个公共 crate 注册表,crates.io。人们使用 cargo publish 发布 crate,并且很容易将这些 crate 包含在 Cargo.toml[dependencies] 部分中。

但是,并非每个人都希望将其 crate 发布到 crates.io。维护专有/闭源代码的人员不能使用 crates.io,而是被迫使用 gitpath 依赖项。这对于小型项目来说通常可以接受,但是如果大型组织内有大量闭源 crate,那么您将失去 crates.io 拥有的版本控制支持的优势。

在此版本中,Cargo 获得了对备用注册表的支持。这些注册表与 crates.io 共存,因此您可以编写依赖于来自 crates.io 和自定义注册表的 crate 的软件。但是,crates.io 上的 crate 不能依赖于外部注册表。

要使用备用注册表,您必须将以下行添加到您的 .cargo/config。此文件可以位于您的主目录 (~/.cargo/config) 或相对于包目录。

[registries]
my-registry = { index = "https://my-intranet:8080/git/index" }

依赖备用注册表中的 crate 很简单。在您的 Cargo.toml 中指定依赖项时,使用 registry 键来告诉 Cargo 您希望从备用注册表获取 crate

[dependencies]
other-crate = { version = "1.0", registry = "my-registry" }

作为 crate 作者,如果您希望将 crate 发布到备用注册表,则首先需要使用 cargo login 命令将身份验证令牌保存到 ~/.cargo/credentials

cargo login --registry=my-registry

然后,您可以使用 --registry 标志来指示发布时要使用哪个注册表

cargo publish --registry=my-registry

关于如何运行自己的注册表,请参阅文档

文档测试中的 ?

RFC 1937 提出在 fn main()#[test] 函数和 doctest 中添加对使用 ? 运算符的支持,允许它们返回 Option<T>Result<T, E>,其中错误值在 fn main() 的情况下导致非零退出代码,在测试的情况下导致测试失败。

fn main()#[test] 的支持在很多版本之前就已经实现。但是,对文档测试中的支持仅限于具有显式 fn main() 的 doctest。

在此版本中,已添加对 doctest 中 ? 的完全支持。现在,您可以在文档测试中编写如下代码:

/// ```rust
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok::<(), io::Error>(())
/// ```
fn my_func() {}

您仍然必须在文档测试的底部指定正在使用的错误类型。

自定义属性接受任意标记流

Rust 中的过程宏可以定义它们使用的自定义属性。到目前为止,此类属性被限制为根据特定语法组成的路径和字面量的树,例如

#[foo(bar)]
#[foo = "bar"]
#[foo = 0]
#[foo(bar = true)]
#[foo(bar, baz(quux, foo = "bar"))]

与过程宏不同,这些辅助属性不能接受分隔符中的任意标记流,因此您不能编写 #[range(0..10)]#[bound(T: MyTrait)]。过程宏 crate 将使用字符串来指定此类语法,例如 #[range("0..10")]

在此 Rust 版本中,自定义属性 #[attr($tokens)] 现在接受 $tokens 中的任意标记流,使它们与宏相提并论。如果您是过程宏 crate 的作者,请检查您的自定义属性的语法中是否有不必要的字符串,以及是否可以使用标记流更好地表达它们。

TryFromTryInto

TryFromTryInto trait 已被稳定化,以允许可失败的类型转换。

例如,整数类型上的 from_be_bytes 和相关方法采用数组,但数据通常通过切片读取。手动在切片和数组之间进行转换很繁琐。使用新 trait,可以使用 .try_into() 内联完成。

let num = u32::from_be_bytes(slice.try_into()?);

对于不会失败的转换(例如 u8u32),添加了 Infallible 类型。这也允许为所有现有的 From 实现提供 TryFrom 的通用实现。在将来,我们希望将 Infallible 转换为 ! (never) 类型的别名。

fn before_exec 已弃用,改为使用 unsafe fn pre_exec

在类 Unix 系统上,函数 CommandExt::before_exec 允许您在调用 exec 之前安排一个闭包运行。

提供的闭包将在 fork 之后在子进程的上下文中运行。这意味着诸如文件描述符和内存映射区域之类的资源可能会被复制。换句话说,您现在可以将非 Copy 类型的值复制到不同的进程中,同时在父进程中保留原始值。这使得有可能导致未定义的行为并破坏假设非重复的库

因此,函数 before_exec 应该标记为 unsafe。在此 Rust 版本中,我们已弃用 fn before_exec,而改用 unsafe fn pre_exec。在调用 CommandExt::pre_exec 时,您有责任确保闭包不会通过无效使用这些重复项来违反库的不变量。如果您提供与 before_exec 情况类似的库,请考虑弃用并提供 unsafe 的替代方案。

库的稳定化

在 1.34.0 中,稳定的原子整数类型集已扩展,现在可以使用从 8 (AtomicU8) 到 64 位的有符号和无符号变体。

先前,非零无符号整数类型(例如 NonZeroU8)已稳定。这使得 Option<NonZeroU8> 的大小与 u8 相同。在此 Rust 版本中,有符号版本(例如 NonZeroI8)已稳定。

函数 iter::from_fniter::successors 已稳定。前者允许您从 FnMut() -> Option<T> 构造迭代器。要迭代地从向量中弹出元素,您现在可以编写 from_fn(|| vec.pop())。同时,后者创建一个新的迭代器,其中每个连续项都基于前一项计算得出。

此外,以下 API 已稳定:

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