诊断属性
以下 属性 用于在编译期间控制或生成诊断消息。
Lint 检查属性
Lint 检查命名了一种潜在的不良编码模式,例如无法访问的代码或遗漏的文档。
lint 属性 allow
、expect
、warn
、deny
和 forbid
使用 MetaListPaths 语法来指定要更改属性应用实体的 lint 级别的 lint 名称列表。
对于任何 lint 检查 C
#[allow(C)]
覆盖对C
的检查,因此违规行为将不会报告。
#[expect(C)]
表示预期会发出 lintC
。如果期望未实现,则该属性将抑制C
的发出或发出警告。
#[warn(C)]
警告关于C
的违规行为,但继续编译。
#[deny(C)]
在遇到C
的违规行为后发出错误信号。
#[forbid(C)]
与deny(C)
相同,但也禁止之后更改 lint 级别。
注意:
rustc
支持的 lint 检查可以通过rustc -W help
找到,以及它们的默认设置,并在 rustc book 中记录。
Lint 属性可以覆盖先前属性指定的级别,只要该级别不尝试更改禁止的 lint(deny
除外,它允许在 forbid
上下文中使用,但会被忽略)。先前的属性是指语法树中更高级别的属性,或源文件中从左到右列出的同一实体上的先前属性。
此示例展示了如何使用 allow
和 warn
来切换特定检查的开启和关闭
此示例展示了如何使用 forbid
来禁止对该 lint 检查使用 allow
或 expect
Lint 原因
所有 lint 属性都支持额外的 reason
参数,以提供添加特定属性的上下文原因。如果 lint 在定义的级别发出,则此原因将显示为 lint 消息的一部分。
这是另一个示例,其中 lint 被允许并带有一个原因
#[expect]
属性
#[expect(C)]
属性为 lint C
创建一个 lint 期望。如果同一位置的 #[warn(C)]
属性将导致 lint 发出,则该期望将被实现。如果期望未实现,因为 lint C
不会被发出,则将在该属性处发出 unfulfilled_lint_expectations
lint。
fn main() {
// This `#[expect]` attribute creates a lint expectation, that the `unused_variables`
// lint would be emitted by the following statement. This expectation is
// unfulfilled, since the `question` variable is used by the `println!` macro.
// Therefore, the `unfulfilled_lint_expectations` lint will be emitted at the
// attribute.
#[expect(unused_variables)]
let question = "who lives in a pineapple under the sea?";
println!("{question}");
// This `#[expect]` attribute creates a lint expectation that will be fulfilled, since
// the `answer` variable is never used. The `unused_variables` lint, that would usually
// be emitted, is suppressed. No warning will be issued for the statement or attribute.
#[expect(unused_variables)]
let answer = "SpongeBob SquarePants!";
}
lint 期望仅由被 expect
属性抑制的 lint 发出实现。如果在作用域中使用其他级别属性(如 allow
或 warn
)修改了 lint 级别,则 lint 发出将相应地处理,并且期望将保持未实现状态。
如果 expect
属性包含多个 lint,则每个 lint 都是单独期望的。对于一个 lint 组,如果组内的一个 lint 已发出就足够了。
注意:
#[expect(unfulfilled_lint_expectations)]
的行为当前被定义为始终生成unfulfilled_lint_expectations
lint。
Lint 组
Lint 可以组织成命名组,以便可以一起调整相关 lint 的级别。使用命名组等效于列出该组内的 lint。
有一个名为 “warnings” 的特殊组,其中包括所有 “warn” 级别的 lint。“warnings” 组忽略属性顺序,并应用于实体内所有原本会发出警告的 lint。
工具 lint 属性
工具 lint 允许使用作用域 lint,以 allow
、warn
、deny
或 forbid
特定工具的 lint。
工具 lint 仅在关联的工具处于活动状态时才会被检查。如果 lint 属性(例如 allow
)引用了不存在的工具 lint,则编译器在您使用该工具之前不会警告不存在的 lint。
否则,它们的工作方式与常规 lint 属性完全相同。
// 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() {
// ...
}
deprecated
属性
deprecated
属性 将项目标记为已弃用。rustc
将在使用 #[deprecated]
项目时发出警告。rustdoc
将显示项目弃用信息,包括 since
版本和 note
(如果可用)。
deprecated
属性有几种形式
deprecated
— 发出通用消息。deprecated = "message"
— 在弃用消息中包含给定的字符串。- MetaListNameValueStr 语法,带有两个可选字段
since
— 指定项目被弃用的版本号。rustc
当前不解释该字符串,但像 Clippy 这样的外部工具可能会检查该值的有效性。note
— 指定应包含在弃用消息中的字符串。这通常用于提供关于弃用和首选替代方案的解释。
deprecated
属性可以应用于任何 项目、trait 项目、枚举变体、结构体字段、外部块项目 或 宏定义。它不能应用于 trait 实现项目。当应用于包含其他项目的项目(例如 模块 或 实现)时,所有子项目都继承弃用属性。
这是一个例子
RFC 包含动机和更多详细信息。
must_use
属性
must_use
属性 用于在值未“使用”时发出诊断警告。
must_use
属性可以应用于用户定义的复合类型(struct
、enum
和 union
)、函数 和 trait。
must_use
属性可以包含消息,方法是使用 MetaNameValueStr 语法,例如 #[must_use = "example message"]
。该消息将与警告一起给出。
当用于用户定义的复合类型时,如果 表达式 的 表达式语句 具有该类型,则会违反 unused_must_use
lint。
当用于函数时,如果 表达式 的 表达式语句 是对该函数的 调用表达式,则会违反 unused_must_use
lint。
当用于 trait 声明 时,对返回该 trait 的 impl trait 或 dyn trait 的函数的 调用表达式 的 表达式语句 会违反 unused_must_use
lint。
当用于 trait 声明中的函数时,当调用表达式是来自 trait 实现的函数时,该行为也适用。
当用于 trait 实现中的函数时,该属性不起作用。
注意:包含该值的琐碎的空操作表达式不会违反 lint。示例包括将该值包装在不实现
Drop
的类型中,然后不使用该类型,并成为未使用的 块表达式 的最终表达式。
注意:当有意丢弃 must-use 值时,习惯用法是使用带有
_
模式的 let 语句。
diagnostic
工具属性命名空间
#[diagnostic]
属性命名空间是用于存放影响编译时错误消息的属性的地方。这些属性提供的提示不保证会被使用。
此命名空间中未知的属性被接受,尽管它们可能会为未使用的属性发出警告。此外,已知属性的无效输入通常会发出警告(有关详细信息,请参见属性定义)。这旨在允许在将来添加或丢弃属性并更改输入,从而允许更改,而无需保持无意义的属性或选项工作。
diagnostic::on_unimplemented
属性
#[diagnostic::on_unimplemented]
属性是编译器的提示,用于补充在 trait 是必需的但在类型上未实现的情况下通常生成的错误消息。
该属性应放置在 trait 声明 上,尽管放置在其他位置不是错误。
- tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
- tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.rs
- tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.rs
- tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs
该属性使用 MetaListNameValueStr 语法来指定其输入,尽管属性的任何格式错误的输入都不会被视为错误,以提供向前和向后兼容性。
以下键具有给定的含义
message
— 顶级错误消息的文本。label
— 错误消息中内联在错误代码中显示的标签文本。note
— 提供额外的注释。
note
选项可以出现多次,这将导致发出多条注释消息。
如果任何其他选项出现多次,则相关选项的第一次出现指定实际使用的值。后续的出现会生成警告。
对于任何未知键都会生成警告。
所有三个选项都接受字符串作为参数,使用与 std::fmt
字符串相同的格式进行解释。
带有给定命名参数的格式参数将被替换为以下文本
{Self}
— 实现 trait 的类型的名称。{
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
diagnostic::do_not_recommend
属性
#[diagnostic::do_not_recommend]
属性是编译器的提示,用于不将带注释的 trait 实现显示为诊断消息的一部分。
注意:如果您知道建议通常对程序员无用,则抑制建议可能很有用。这种情况通常发生在广泛的、通用的 impl 中。该建议可能会将程序员引向错误的道路,或者 trait 实现可能是您不想公开的内部细节,或者程序员可能无法满足 bounds。
例如,在关于类型未实现所需 trait 的错误消息中,编译器可能会找到一个 trait 实现,如果不是 trait 实现中的特定 bounds,它将满足要求。编译器可能会告诉用户存在一个 impl,但问题在于 trait 实现中的 bounds。
#[diagnostic::do_not_recommend]
属性可用于告诉编译器不要告诉用户 trait 实现,而是简单地告诉用户该类型未实现所需的 trait。
该属性应放置在 trait 实现项目 上,尽管放置在其他位置不是错误。
该属性不接受任何参数,尽管意外的参数不会被视为错误。
在以下示例中,有一个名为 AsExpression
的 trait,用于将任意类型转换为 SQL 库中使用的 Expression
类型。有一个名为 check
的方法,它接受 AsExpression
。
SelectInt
类型的 check
方法期望 Integer
类型。使用 i32 类型调用它可以工作,因为它通过 AsExpression
trait 转换为 Integer
。但是,使用字符串调用它不起作用,并生成一个可能如下所示的错误
error[E0277]: the trait bound `&str: Expression` is not satisfied
--> src/main.rs:53:15
|
53 | SelectInt.check("bar");
| ^^^^^ the trait `Expression` is not implemented for `&str`
|
= help: the following other types implement trait `Expression`:
Bound<T>
SelectInt
note: required for `&str` to implement `AsExpression<Integer>`
--> src/main.rs:45:13
|
45 | impl<T, ST> AsExpression<ST> for T
| ^^^^^^^^^^^^^^^^ ^
46 | where
47 | T: Expression<SqlType = ST>,
| ------------------------ unsatisfied trait bound introduced here
通过将 #[diagnostic::do_no_recommend]
属性添加到 AsExpression
的通用 impl
,消息更改为
error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
--> src/main.rs:53:15
|
53 | SelectInt.check("bar");
| ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
|
= help: the trait `AsExpression<Integer>` is not implemented for `&str`
but trait `AsExpression<Text>` is implemented for it
= help: for that trait implementation, expected `Text`, found `Integer`
第一个错误消息包含关于 &str
和 Expression
关系以及通用 impl 中未满足的 trait bound 的一些令人困惑的错误消息。添加 #[diagnostic::do_no_recommend]
后,它不再考虑通用 impl 作为建议。该消息应该更清晰一些,指示字符串无法转换为 Integer
。