诊断属性

下面的 属性 用于在编译期间控制或生成诊断信息。

代码分析检查属性

代码分析检查指的是一些可能存在不良编码模式的代码,例如不可到达的代码或省略的文档。 代码分析属性 allowwarndenyforbid 使用 元列表路径组 语法指定要更改为应用属性的实体的代码分析级别列表。

对于任何代码分析检查 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 }
}
}

代码分析属性可以覆盖先前属性中指定的级别,只要级别不会试图更改禁止的代码分析。 先前的属性来自语法树中更高级别的属性,或者是源代码中从左到右的先前属性。

以下示例展示了如何使用 allowwarn 来打开和关闭特定检查:

#![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 }
}
}

注意:rustc 允许在 命令行 上设置代码分析级别,并支持在报告的代码分析上 设置限制

代码分析组

代码分析可以被组织成具有名称的组,以便可以一起调整相关代码分析的级别。使用命名组相当于列出该组中的代码分析。

#![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() {
// ...
}

注意: 目前 rustc 只支持 "clippy" 和 "rustdoc" 的工具代码分析。

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 属性 用于在值未被 "使用" 时发出诊断警告。它可以应用于用户定义的复合类型 ( structenumunion ) 、 functionstraits

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 traitdyn 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();
}