4个版本
使用旧的Rust 2015
0.1.3 | 2018年12月4日 |
---|---|
0.1.2 | 2017年2月23日 |
0.1.1 | 2017年2月23日 |
0.1.0 | 2017年2月23日 |
#1686 in Rust模式
11KB
incomplete
此crate提供 incomplete!()
,它是 unimplemented!()
的编译时检查版本。
关于此宏的动机和讨论可以在 rust-internals 线程中找到,以及 RFC问题。以下是一些重复的内容。
我们都熟悉并喜爱 unimplemented!()
宏,用于跟踪我们尚未着手的事情。然而,它仅在遇到特定的代码路径时进行运行时检查。这在许多情况下都很好,例如对于你尚未预料到需要处理的边缘情况。但是,当你从头开始编写新代码(特别是当移植时)、重构大量代码或构建全新的功能时,你通常会有一些尚未实现的代码段,但你 知道 你将不得不实现它们。
此宏的基本动机是引入一个结构,指示一段代码 需要 填充(即,程序在存在时不应编译),但开发人员希望推迟到以后编写。
例如,考虑一个需要将所有 Foo
和 Bar
替换为 Baz
的重构。大多数转换都很直接,但一些需要更深入的改变(例如,Baz
需要一些在特定代码段中不可直接获得的其他值)。你可能首先完成翻译所有 Foo
和 Bar
,然后再处理边缘情况。
通常情况下,开发者可能会添加一个 // TODO
注释,或者一个 unimplemented!()
语句。然而,这种方法有一些缺点。特别是,这两种方法仍然允许代码在存在的情况下编译。因此,在“第一次遍历”之后,开发者必须 记住 同时 grep 所有 unimplemented()
和 // TODO
(并且 过滤掉任何与问题重构无关的)。
这个 crate 实现的宏提供了一种方式,告诉编译器“在未实现时不要让代码编译”,同时运行类型检查和借用检查,这样你就可以在同时完成其他代码段。
理想情况下,这个宏会有自己的编译器 lint,使得生成的错误直接表示“所需代码段未完成”。然而,直到 RFC 问题 1911 有所进展,这个 crate 通过“滥用”另一个 lint 并将其变成一个致命警告来解决这个问题。结果基本上符合预期:它只有在所有编译器遍历都成功完成之后才会出错,它可以作为一个语句或表达式来评估。
示例
#[macro_use] extern crate incomplete;
fn foo() -> bool {
incomplete!()
}
fn main() {
foo();
}
产生
error: value assigned to `incomplete` is never read
--> src/main.rs:5:5
|
5 | incomplete!()
| ^^^^^^^^^^^^^
|
注意事项
截至编写本文时,稳定的编译器在 incomplete!()
被使用时只会产生 警告,而不是 错误。这是因为它没有正确解释语句上编译器指令的使用。在 nightly 上这个问题已经被修复。
此外,这个宏在幕后“滥用”了一个现有的 Rust 编译器 lint。由于编译器坚持告诉你每个 lint 警告转换成错误的来源,不幸的是,你也会收到类似的消息
note: lint level defined here
--> src/main.rs:5:13
|
5 | let x = incomplete!(bool);
| ^^^^^^^^^^^^^^^^^
= note: this error originates in a macro outside of the current crate