诊断属性

以下 属性 用于在编译期间控制或生成诊断消息。

代码检查属性

代码检查是指可能不希望出现的编码模式,例如不可达代码或省略的文档。代码检查属性 allowwarndenyforbid 使用 MetaListPaths 语法来指定要更改其代码检查级别的实体的代码检查名称列表。

对于任何代码检查 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 {
    // Missing documentation is ignored here
    #[allow(missing_docs)]
    pub fn undocumented_one() -> i32 { 1 }

    // Missing documentation signals a warning here
    #[warn(missing_docs)]
    pub fn undocumented_too() -> i32 { 2 }

    // Missing documentation signals an error here
    #[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 {
        // Missing documentation is ignored here
        pub fn undocumented_one() -> i32 { 1 }

        // Missing documentation signals a warning here,
        // despite the allow above.
        #[warn(missing_docs)]
        pub fn undocumented_two() -> i32 { 2 }
    }

    // Missing documentation signals a warning here
    pub fn undocumented_too() -> i32 { 3 }
}
}

此示例显示了如何使用 forbid 来禁止对该代码检查使用 allow

#![allow(unused)]
fn main() {
#[forbid(missing_docs)]
pub mod m3 {
    // Attempting to toggle warning signals an error here
    #[allow(missing_docs)]
    /// Returns 2.
    pub fn undocumented_too() -> i32 { 2 }
}
}

注意:rustc 允许在 命令行 上设置代码检查级别,并且还支持 设置 报告的代码检查的 上限

代码检查组

代码检查可以组织成命名组,以便可以一起调整相关代码检查的级别。使用命名组等同于列出该组内的代码检查。

#![allow(unused)]
fn main() {
// This allows all lints in the "unused" group.
#[allow(unused)]
// This overrides the "unused_must_use" lint from the "unused"
// group to deny.
#[deny(unused_must_use)]
fn example() {
    // This does not generate a warning because the "unused_variables"
    // lint is in the "unused" group.
    let x = 1;
    // This generates an error because the result is unused and
    // "unused_must_use" is marked as "deny".
    std::fs::remove_file("some_file"); // ERROR: unused `Result` that must be used
}
}

有一个名为“warnings”的特殊组,其中包括所有处于“warn”级别的代码检查。“warnings”组忽略属性顺序,并应用于实体中所有否则会发出警告的代码检查。

#![allow(unused)]
fn main() {
unsafe fn an_unsafe_fn() {}
// The order of these two attributes does not matter.
#[deny(warnings)]
// The unsafe_code lint is normally "allow" by default.
#[warn(unsafe_code)]
fn example_err() {
    // This is an error because the `unsafe_code` warning has
    // been lifted to "deny".
    unsafe { an_unsafe_fn() } // ERROR: usage of `unsafe` block
}
}

工具代码检查属性

工具代码检查允许使用作用域代码检查,以 allowwarndenyforbid 某些工具的代码检查。

工具代码检查仅在关联工具处于活动状态时才会被检查。如果代码检查属性(例如 allow)引用了不存在的工具代码检查,则编译器在您使用该工具之前不会警告该不存在的代码检查。

否则,它们的工作方式与常规代码检查属性相同

// set the entire `pedantic` clippy lint group to warn
#![warn(clippy::pedantic)]
// silence warnings from the `filter_map` clippy lint
#![allow(clippy::filter_map)]

fn main() {
    // ...
}

// silence the `cmp_nan` clippy lint just for this function
#[allow(clippy::cmp_nan)]
fn foo() {
    // ...
}

注意:rustc 目前识别“clippy”和“rustdoc”的工具代码检查。

deprecated 属性

deprecated 属性 将项目标记为已弃用。rustc 将在使用 #[deprecated] 项目时发出警告。如果可用,rustdoc 将显示项目弃用信息,包括 since 版本和 note

deprecated 属性有几种形式

  • deprecated — 发出通用消息。
  • deprecated = "message" — 在弃用消息中包含给定的字符串。
  • MetaListNameValueStr 语法,包含两个可选字段
    • since — 指定项目何时被弃用的版本号。rustc 目前不解释该字符串,但像 Clippy 这样的外部工具可能会检查该值的有效性。
    • note — 指定应包含在弃用消息中的字符串。这通常用于提供有关弃用和首选替代方案的说明。

deprecated 属性可以应用于任何 特征项枚举成员结构体字段外部块项宏定义。它不能应用于 特征实现项。当应用于包含其他项的项时,例如 模块实现,所有子项都继承弃用属性。

以下是一个示例

#![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)、函数特征

must_use 属性可以使用 MetaNameValueStr 语法包含一条消息,例如 #[must_use = "示例消息"]。该消息将与警告一起给出。

当用于用户定义的复合类型时,如果 表达式语句表达式 具有该类型,则会违反 unused_must_use lint。

#![allow(unused)]
fn main() {
#[must_use]
struct MustUse {
    // some fields
}

impl MustUse {
  fn new() -> MustUse { MustUse {} }
}

// Violates the `unused_must_use` lint.
MustUse::new();
}

当用于函数时,如果 表达式语句表达式 是对该函数的 调用表达式,则会违反 unused_must_use lint。

#![allow(unused)]
fn main() {
#[must_use]
fn five() -> i32 { 5i32 }

// Violates the unused_must_use lint.
five();
}

当用于 特征声明 时,如果 表达式语句调用表达式 是对返回该特征的 impl traitdyn trait 的函数的调用,则会违反 unused_must_use lint。

#![allow(unused)]
fn main() {
#[must_use]
trait Critical {}
impl Critical for i32 {}

fn get_critical() -> impl Critical {
    4i32
}

// Violates the `unused_must_use` lint.
get_critical();
}

当用于特征声明中的函数时,当调用表达式是来自特征实现的函数时,该行为也适用。

#![allow(unused)]
fn main() {
trait Trait {
    #[must_use]
    fn use_me(&self) -> i32;
}

impl Trait for i32 {
    fn use_me(&self) -> i32 { 0i32 }
}

// Violates the `unused_must_use` lint.
5i32.use_me();
}

当用于特征实现中的函数时,该属性不起作用。

注意:包含该值的平凡无操作表达式不会违反 lint。例如,将值包装在未实现 Drop 的类型中,然后不使用该类型,并且是未使用的 块表达式 的最终表达式。

#![allow(unused)]
fn main() {
#[must_use]
fn five() -> i32 { 5i32 }

// None of these violate the unused_must_use lint.
(five(),);
Some(five());
{ five() };
if true { five() } else { 0i32 };
match true {
    _ => five()
};
}

注意:当有意丢弃必须使用的值时,习惯上使用带有 _ 模式的 let 语句

#![allow(unused)]
fn main() {
#[must_use]
fn five() -> i32 { 5i32 }

// Does not violate the unused_must_use lint.
let _ = five();
}

diagnostic 工具属性命名空间

#[diagnostic] 属性命名空间是用于影响编译时错误消息的属性的所在地。这些属性提供的提示不保证会被使用。此命名空间中的未知属性会被接受,但它们可能会针对未使用的属性发出警告。此外,对已知属性的无效输入通常会产生警告(有关详细信息,请参阅属性定义)。这样做是为了允许在将来添加或丢弃属性并更改输入,以便在无需保持无意义的属性或选项工作的情况下进行更改。

diagnostic::on_unimplemented 属性

#[diagnostic::on_unimplemented] 属性是编译器的提示,用于补充在需要特征但未在类型上实现特征的情况下通常会生成的错误消息。该属性应放在 特征声明 上,但在其他位置使用它不会出错。该属性使用 MetaListNameValueStr 语法来指定其输入,但对该属性的任何格式错误的输入都不会被视为错误,以提供向前和向后兼容性。以下键具有给定的含义

  • message — 顶级错误消息的文本。
  • label — 错误消息中损坏代码中显示的标签的文本。
  • note — 提供其他注释。

note 选项可以出现多次,这会导致发出多条注释消息。如果任何其他选项出现多次,则相关选项的第一次出现指定实际使用的值。任何其他出现都会生成 lint 警告。对于任何其他不存在的选项,都会生成 lint 警告。

所有三个选项都接受一个字符串作为参数,使用与 std::fmt 字符串相同的格式进行解释。具有给定命名参数的格式参数将替换为以下文本

  • {Self} — 实现特征的类型的名称。
  • { GenericParameterName } — 给定泛型参数的泛型参数类型的名称。

任何其他格式参数都会生成警告,但除此之外将按原样包含在字符串中。

无效的格式字符串可能会生成警告,但在其他情况下是允许的,但可能无法按预期显示。格式说明符可能会生成警告,但在其他情况下会被忽略。

在这个例子中

#[diagnostic::on_unimplemented(
    message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`",
    label = "My Label",
    note = "Note 1",
    note = "Note 2"
)]
trait ImportantTrait<A> {}

fn use_my_trait(_: impl ImportantTrait<i32>) {}

fn main() {
    use_my_trait(String::new());
}

编译器可能会生成如下所示的错误消息

error[E0277]: My Message for `ImportantTrait<i32>` implemented for `String`
  --> src/main.rs:14:18
   |
14 |     use_my_trait(String::new());
   |     ------------ ^^^^^^^^^^^^^ My Label
   |     |
   |     required by a bound introduced by this call
   |
   = help: the trait `ImportantTrait<i32>` is not implemented for `String`
   = note: Note 1
   = note: Note 2