Rust 团队很高兴宣布 Rust 的新版本 1.30.0。Rust 是一种专注于安全性、速度和并发性的系统编程语言。
如果您已经通过 rustup 安装了之前的 Rust 版本,那么获取 Rust 1.30.0 非常简单,只需运行
如果您尚未安装,可以从我们网站的相应页面获取 rustup,并在 GitHub 上查阅 1.30.0 的详细发行说明。
1.30.0 stable 中有什么
Rust 1.30 是一个令人兴奋的版本,包含许多特性。周一,预计会发布另一篇博客文章,请您试用 Rust 1.31 的 beta 版本;Rust 1.31 将是“Rust 2018”的第一个版本。有关该概念的更多信息,请参阅我们之前的文章 “什么是 Rust 2018”。
过程宏
早在 Rust 1.15 中,我们就宣布了定义“自定义派生(custom derives)”的能力。例如,使用 serde_derive,您可以
并使用 serde_json 将 Pet 转换为 JSON 或从 JSON 转换,因为 serde_derive 在一个过程宏中定义了 Serialize 和 Deserialize。
Rust 1.30 在此基础上进行了扩展,增加了定义另外两种高级宏的能力:“类属性过程宏(attribute-like procedural macros)”和“类函数过程宏(function-like procedural macros)”。
类属性宏类似于自定义派生宏,但它们不仅为 #[derive] 属性生成代码,还允许您创建自己的新自定义属性。它们也更灵活:派生(derive)只适用于结构体和枚举,但属性可以用于其他地方,例如函数。以下是使用类属性宏的示例,在使用 Web 应用框架时您可能会看到类似这样的代码
#[route(GET, "/")]
fn index() {
这个 #[route] 属性将由框架本身定义,作为一个过程宏。它的签名会是这样
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
这里,我们有两个输入 TokenStreams:第一个用于属性本身的内容,即 GET, "/" 等内容。第二个是属性所附加的内容体,在本例中是 fn index() {} 以及函数体的其余部分。
类函数宏定义了看起来像函数调用的宏。例如,gnome-class crate 有一个过程宏,用于在 Rust 中定义 GObject 类
gobject_gen!
这看起来像一个将一堆代码作为参数的函数。这个宏的定义方式如下
#[proc_macro]
pub fn gobject_gen(input: TokenStream) -> TokenStream {
这类似于派生宏的签名:我们获取括号内的 token,然后返回我们想要生成的代码。
use 和宏
现在,您可以使用 use 关键字将宏引入作用域。例如,以前使用 serde-json 的 json 宏时,您需要这样写
extern crate serde_json;
let john = json!;
但现在,您可以这样写
extern crate serde_json;
use json;
let john = json!;
这使得宏与其他项的使用方式更加一致,并且不再需要 macro_use 注解。
最后,proc_macro crate 被稳定化,它提供了编写这类宏所需的 API。它还显著改进了错误相关的 API,像 syn 和 quote 这样的 crate 已经在使用它们。例如,之前
会产生这样的错误
error[E0277]: the trait bound `std::thread::Thread: _IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not satisfied
--> src/main.rs:3:10
|
3 | #[derive(Serialize)]
| ^^^^^^^^^ the trait `_IMPL_SERIALIZE_FOR_Demo::_serde::Serialize` is not implemented for `std::thread::Thread`
现在则会产生这样的错误
error[E0277]: the trait bound `std::thread::Thread: serde::Serialize` is not satisfied
--> src/main.rs:7:5
|
7 | bad: std::thread::Thread,
| ^^^ the trait `serde::Serialize` is not implemented for `std::thread::Thread`
模块系统改进
模块系统长期以来一直是 Rust 新手的一个痛点;它的一些规则在实践中令人感到别扭。这些改变是我们正在采取的第一步,以使模块系统感觉更直观。
除了前面提到的宏方面的变化之外,use 还有两处变化。首先是 外部 crate 现在位于 prelude 中,也就是说
// old
let json = from_str;
// new
let json = from_str;
这里的技巧在于,由于 Rust 模块系统的工作方式,‘旧’的写法并非总是必需的
extern crate serde_json;
将一个函数移动到子模块并导致部分代码损坏不是一个很好的体验。现在,它会检查路径的第一部分,看它是否是一个 extern crate,如果是,无论您在模块层级中的哪个位置,都会使用它。
最后,use 还支持将以 crate 开头的路径项引入作用域
// old
use bar;
// or
use bar;
// new
use cratebar;
路径开头的 crate 关键字表示您希望路径从您的 crate 根目录开始。以前,在 use 之后指定的路径总是从 crate 根目录开始,但直接引用项的路径会从本地路径开始,这意味着路径的行为是不一致的
一旦这种风格得到广泛使用,有望使绝对路径更加清晰,并消除开头 :: 的一些不美观之处。
所有这些变化结合起来,使理解路径如何解析变得更加直观。无论您在 use 语句以外的任何地方看到像 a::b::c 这样的路径,您都可以这样问
a是一个 crate 的名称吗?如果是,那么我们在其中寻找b::c。a是关键字crate吗?如果是,那么我们从 crate 根目录寻找b::c。- 否则,我们从模块层级中的当前位置寻找
a::b::c。
use 路径始终从 crate 根目录开始的旧行为仍然适用。但在一次性切换到新风格后,这些规则将统一适用于所有地方的路径,并且在移动代码时,您调整引入(imports)的次数会大大减少。
原始标识符
// define a local variable named `for`
let r#for = true;
// define a function named `for`
#for
// call that function
r#for;
目前,这种用法没有太多实际用例,但在您尝试将 Rust 2015 的 crate 与 Rust 2018 的项目一起使用,反之亦然时,它就会有用,因为这两个版本中的关键字集会有所不同;我们将在即将发布的关于 Rust 2018 的博客文章中详细解释。
no_std 应用
早在 Rust 1.6 中,我们就宣布了 用于构建不依赖标准库的项目而稳定化 no_std 和 libcore。但是有一个限制:您只能构建库,不能构建应用。
有了 Rust 1.30,您可以使用 #[panic_handler] 属性自行实现 panic。这现在意味着您可以构建不使用标准库的应用,而不仅仅是库。
其他内容
最后,您现在可以使用 vis specifier 在宏中 匹配可见性关键字,例如 pub。此外,像 #[rustfmt::skip] 这样的“工具属性(tool attributes)”现在已稳定。然而,像 #[allow(clippy::something)] 这样的工具 lints 尚未稳定。
有关更多信息,请参阅 详细发行说明。
标准库稳定化
Ipv4Addr::{BROADCAST, LOCALHOST, UNSPECIFIED}Ipv6Addr::{LOCALHOST, UNSPECIFIED}Iterator::find_map
此外,标准库长期以来一直有像 trim_left 这样的函数,用于去除文本一侧的空白。然而,在考虑从右到左(RTL)的语言时,“右”和“左”的含义会变得令人困惑。因此,我们为这些 API 引入了新的名称
trim_left->trim_starttrim_right->trim_endtrim_left_matches->trim_start_matchestrim_right_matches->trim_end_matches
我们计划在 Rust 1.33 中废弃(当然不是移除)旧名称。
有关更多信息,请参阅 详细发行说明。
Cargo 特性
本次发布中 Cargo 最大的特性是,我们现在 有进度条了!

有关更多信息,请参阅 详细发行说明。
1.30.0 的贡献者
许多人共同努力创建了 Rust 1.30。没有你们,我们不可能完成。 感谢!