诊断属性
下面的 属性 用于在编译期间控制或生成诊断信息。
代码分析检查属性
代码分析检查指的是一些可能存在不良编码模式的代码,例如不可到达的代码或省略的文档。
代码分析属性 allow
、 warn
、 deny
和 forbid
使用 元列表路径组 语法指定要更改为应用属性的实体的代码分析级别列表。
对于任何代码分析检查 C
:
allow(C)
会覆盖C
的检查,使违规不会被报告,warn(C)
警告有关C
的违规,但继续编译。deny(C)
在遇到C
的违规后发出错误信号,forbid(C)
与deny(C)
相同,但还禁止以后更改代码分析级别。
注意:
rustc
支持的代码分析检查可以通过rustc -W help
找到,包括它们的默认设置,并在 rustc 文档 中有记录。
#![allow(unused)] fn main() { pub mod m1 { // 忽略此处的缺失文档 #[allow(missing_docs)] pub fn undocumented_one() -> i32 { 1 } // 此处缺失文档会发出警告 #[warn(missing_docs)] pub fn undocumented_too() -> i32 { 2 } // 此处缺失文档会发出错误 #[deny(missing_docs)] pub fn undocumented_end() -> i32 { 3 } } }
代码分析属性可以覆盖先前属性中指定的级别,只要级别不会试图更改禁止的代码分析。 先前的属性来自语法树中更高级别的属性,或者是源代码中从左到右的先前属性。
以下示例展示了如何使用 allow
和 warn
来打开和关闭特定检查:
#![allow(unused)] fn main() { #[warn(missing_docs)] // 发出警告:缺失文档注释 pub mod m2 { #[allow(missing_docs)] // 忽略警告:缺失文档注释 pub mod nested { // 缺失文档注释,被忽略 pub fn undocumented_one() -> i32 { 1 } // 缺失文档注释,发出警告 // 尽管上面有 allow 指示忽略警告 #[warn(missing_docs)] pub fn undocumented_two() -> i32 { 2 } } // 缺失文档注释,发出警告 pub fn undocumented_too() -> i32 { 3 } } }
这个例子展示了如何使用 forbid
禁止对某个代码分析检查使用 allow
:
#![allow(unused)] fn main() { #[forbid(missing_docs)] pub mod m3 { // 在这里尝试切换警告会导致错误 #[allow(missing_docs)] /// Returns 2. pub fn undocumented_too() -> i32 { 2 } } }
代码分析组
代码分析可以被组织成具有名称的组,以便可以一起调整相关代码分析的级别。使用命名组相当于列出该组中的代码分析。
#![allow(unused)] fn main() { // 这允许所有 "unused" 组中的代码分析。 #[allow(unused)] // 这将 "unused" 组中的 "unused_must_use" 代码分析改为了 "deny"。 #[deny(unused_must_use)] fn example() { // 这不会生成警告,因为 "unused_variables" 代码分析在 "unused" 组中。 let x = 1; // 这会生成一个错误,因为结果未使用且 "unused_must_use" 被标记为 "deny"。 std::fs::remove_file("some_file"); // ERROR: 必须使用的未使用的 `Result` } }
有一个特殊的名为 "warnings" 的分组,其中包括所有 "warn" 级别的代码分析。 "warnings" 分组忽略属性顺序,并适用于实体中所有会产生警告的代码分析。
#![allow(unused)] fn main() { unsafe fn an_unsafe_fn() {} // 这两个属性的顺序无关紧要。 #[deny(warnings)] // unsafe_code 代码分析通常默认为 "allow"。 #[warn(unsafe_code)] fn example_err() { // 这是一个错误,因为 `unsafe_code` 警告已经被提升到了 "deny"。 unsafe { an_unsafe_fn() } // ERROR: 使用 `unsafe` 块 } }
工具代码分析属性
'工具代码分析' 允许使用作用域 '代码分析' ,以允许、警告、禁止某些工具的代码分析。
只有在相关工具处于活动状态时才会检查工具代码分析。
如果像 allow
这样的代码分析属性引用了不存在的 '工具代码分析' ,则编译器在使用该工具之前不会警告不存在的代码分析。
否则,它们的工作方式与常规代码分析属性相同:
// 将整个 pedantic clippy 代码分析组设置为警告 #![warn(clippy::pedantic)] // 屏蔽 filter_map clippy 代码分析中的警告 #![allow(clippy::filter_map)] fn main() { // ... } // 仅针对该函数屏蔽 cmp_nan clippy 代码分析的警告 #[allow(clippy::cmp_nan)] fn foo() { // ... }
deprecated
属性
deprecated
属性 将一个条目标记为已弃用。rustc
在使用被 #[deprecated]
标记的条目时会发出警告。
rustdoc
将显示条目的弃用信息,包括 since
版本和 note
(如果有) 。
deprecated
属性有几种形式:
deprecated
— 发出一条通用信息。deprecated = "message"
— 在弃用消息中包含给定的字符串。- 无列表名称值字符串 语法有两个可选字段:
since
— 指定条目被弃用的版本号。rustc
目前不解释该字符串,但像 Clippy 这样的外部工具可能会检查值的有效性。note
— 指定应在弃用消息中包含的字符串。通常用于提供有关弃用和首选替代方法的解释。
deprecated
属性可应用于任何 条目 、 trait 条目 、 enum 变体 、 struct 字段 、 外部块条目 或 宏定义。
它不能应用于 trait 实现条目。当应用于包含其他条目的条目 (例如 模块 或 实现 )时,所有子条目都继承弃用属性。
以下是一个例子:
#![allow(unused)] fn main() { #[deprecated(since = "5.2.0", note = "foo was rarely used. Users should instead use bar")] pub fn foo() {} pub fn bar() {} }
RFC 包含了动机和更多细节。
must_use
属性
must_use
属性 用于在值未被 "使用" 时发出诊断警告。它可以应用于用户定义的复合类型 ( struct
、 enum
和 union
) 、 functions
和 traits
。
must_use
属性可以通过使用 元名称值字符串 语法 (例如 #[must_use = "example message"]
) 包含一条消息。该消息将与警告一起给出。
当在用户定义的复合类型上使用时,如果 表达式 的 表达式语句 具有该类型,则违反了 unused_must_use
代码分析。
#![allow(unused)] fn main() { #[must_use] struct MustUse { // 一些字段 } impl MustUse { fn new() -> MustUse { MustUse {} } } // 违反了 `unused_must_use` lint. MustUse::new(); }
当应用于函数时,如果 表达式 是对该函数的 调用表达式,那么将违反 unused_must_use
警告。
#![allow(unused)] fn main() { #[must_use] fn five() -> i32 { 5i32 } // 违反了 `unused_must_use` lint. five(); }
当在 trait 声明 上使用时,对该 trait 的 impl trait 或 dyn trait 返回的函数的 调用表达式 的 表达式语句 违反了 unused_must_use
代码代析。
#![allow(unused)] fn main() { #[must_use] trait Critical {} impl Critical for i32 {} fn get_critical() -> impl Critical { 4i32 } // 违反了 `unused_must_use` lint. get_critical(); }
当在 trait 声明中的函数上使用时,当调用表达式是 trait 实现的函数时,该行为也适用。
#![allow(unused)] fn main() { trait Trait { #[must_use] fn use_me(&self) -> i32; } impl Trait for i32 { fn use_me(&self) -> i32 { 0i32 } } // 违反了 `unused_must_use` 代码分析。 5i32.use_me(); }
当用于 trait 实现中的函数时,该属性无效。
注意:包含该值的无关紧要的无操作表达式不会违反代码分析。 例如,将该值包装在未实现
Drop
的类型中,然后不使用该类型,或者是块表达式的最终表达式,而不使用该表达式。
#![allow(unused)] fn main() { #[must_use] fn five() -> i32 { 5i32 } // 这些都不违反 unused_must_use 代码分析。 (five(),); Some(five()); { five() }; if true { five() } else { 0i32 }; match true { _ => five() }; }
注意:当有一个有意舍弃的必须使用的值时,使用带有
_
模式的 let 语句是惯用的写法。#![allow(unused)] fn main() { #[must_use] fn five() -> i32 { 5i32 } // 不违反 unused_must_use 代码分析。 let _ = five(); }