Rust 团队很高兴宣布 Rust 的新版本 1.34.0 已发布。Rust 是一门赋予每个人构建可靠且高效软件能力的编程语言。
如果你之前使用 rustup 安装过 Rust,升级到 Rust 1.34.0 非常简单,只需运行:
$ rustup update stable
如果你还没有安装,你可以从我们网站上的相应页面获取 rustup。
1.34.0 stable 版本有什么新特性
此版本中最重要的特性是引入了备用 cargo 注册表。此版本还包括在文档测试中支持 ? 运算符、对 #[attribute(..)] 的一些改进,以及 TryFrom 的稳定化。请继续阅读以了解更多亮点,或参阅详细发布说明以获取更多信息。
备用 cargo 注册表
早在 1.0 版本之前,Rust 就拥有一个公共 crate 注册表:crates.io。人们使用 cargo publish 发布 crate,并且可以轻松地将这些 crate 包含在 Cargo.toml 文件的 [dependencies] 部分中。
然而,并非所有人都希望将其 crate 发布到 crates.io。维护专有/闭源代码的人无法使用 crates.io,而是被迫使用 git 或 path 依赖。这对于小型项目通常没有问题,但如果在一个大型组织内有很多闭源 crate,你将失去 crates.io 提供的版本控制支持的好处。
通过此版本,Cargo 增加了对备用注册表的支持。这些注册表与 crates.io 并存,因此你可以编写依赖于 crates.io 和自定义注册表中 crate 的软件。但是,crates.io 上的 crate 不能依赖外部注册表。
要使用备用注册表,你必须将这些行添加到你的 .cargo/config 文件中。此文件可以位于你的主目录(~/.cargo/config)或包目录中。
[]
= { = "https://my-intranet:8080/git/index" }
依赖来自备用注册表的 crate 非常简单。在 Cargo.toml 中指定依赖时,使用 registry 键告诉 Cargo 你希望从备用注册表获取该 crate。
[]
= { = "1.0", = "my-registry" }
作为 crate 作者,如果你希望将你的 crate 发布到备用注册表,首先需要使用 cargo login 命令将认证令牌保存到 ~/.cargo/credentials 文件中。
然后,你可以使用 --registry 标志来指示发布时使用哪个注册表。
有关如何运行自己的注册表,请参阅文档。
文档测试中的 ? 运算符
RFC 1937 提议在 fn main() 函数、#[test] 函数和文档测试中添加对使用 ? 运算符的支持,允许它们返回 Option<T> 或 Result<T, E>;在 fn main() 的情况下,错误值会导致非零退出码,而在测试的情况下,错误值会导致测试失败。
在 fn main() 和 #[test] 中对 ? 的支持已在之前的多个版本中实现。然而,文档测试中的支持仅限于具有显式 fn main() 的 doctests。
在此版本中,文档测试中对 ? 运算符的完整支持已被添加。现在,你可以在文档测试中这样写:
/// ```rust
/// use std::io;
/// let mut input = String::new();
/// io::stdin().read_line(&mut input)?;
/// # Ok::<(), io::Error>(())
/// ```
你仍然需要在文档测试的底部指定所使用的错误类型。
自定义属性接受任意 token 流
Rust 中的过程宏可以定义它们消耗的自定义属性。到目前为止,此类属性被限制为根据特定语法组成的路径和字面量树,例如
与过程宏不同,这些辅助属性不能接受分隔符中的任意 token 流,因此你不能编写 #[range(0..10)] 或 #[bound(T: MyTrait)]。过程宏 crate 通常会使用字符串来指定这样的语法,例如 #[range("0..10")]
随着此 Rust 版本的发布,自定义属性 #[attr($tokens)] 现在接受 $tokens 中的任意 token 流,使其与宏处于同等地位。如果你是过程宏 crate 的作者,请检查你的自定义属性语法中是否有不必要的字符串,以及它们是否可以使用 token 流更好地表达。
TryFrom 和 TryInto
TryFrom 和 TryInto trait 已稳定化,以允许可能失败的类型转换。
例如,整数类型上的 from_be_bytes 和相关方法接受数组,但数据通常是通过切片读取的。手动在切片和数组之间进行转换很繁琐。有了新的 trait,可以使用 .try_into() 进行内联转换。
let num = u32from_be_bytes;
对于不会失败的转换,例如 u8 到 u32,添加了 Infallible 类型。这还允许为所有现有的 From 实现提供一个泛化实现(blanket implementation)的 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 时,你有责任确保闭包不会因为不当使用这些复制资源而违反库的不变性(invariants)。如果你提供的库存在类似于 before_exec 的情况,也请考虑弃用并提供一个 unsafe 替代方案。
库稳定化
在 1.34.0 中,稳定化的原子整数类型集合得到了扩展,现在提供了从 8 (AtomicU8) 到 64 位的有符号和无符号变体。
之前,非零无符号整数类型,例如 NonZeroU8,已稳定化。这使得 Option<NonZeroU8> 的大小与 u8 相同。在此 Rust 版本中,有符号版本,例如 NonZeroI8,也已稳定化。
函数 iter::from_fn 和 iter::successors 已稳定化。前者允许你从一个 FnMut() -> Option<T> 构造一个迭代器。要迭代地从 vector 中弹出元素,你现在可以写 from_fn(|| vec.pop())。同时,后者创建一个新的迭代器,其中每个后续项都基于前一项计算得出。
此外,以下 API 也已稳定化:
- Any::type_id
- Error::type_id
- slice::sort_by_cached_key
- str::escape_debug
- str::escape_default
- str::escape_unicode
- str::split_ascii_whitespace
- Instant::checked_add
- Instant::checked_sub
- SystemTime::checked_add
- SystemTime::checked_sub
更多详情请参阅详细发布说明。