属性
Syntax
InnerAttribute → # ! [ Attr ]
OuterAttribute → # [ Attr ]
Attr →
SimplePath AttrInput?
| unsafe ( SimplePath AttrInput? )
一个 属性 是一个通用的、自由形式的元数据,根据名称、约定、语言和编译器版本进行解释。属性的建模基于 ECMA-335 中的属性,其 语法格式 源自 ECMA-334 (C#)。
内部属性,写在哈希符号 (#) 后带一个感叹号 (!),适用于声明该属性的所在形式。
例子
#![allow(unused)] fn main() { // 适用于 enclosing 模块或 crate 的通用元数据。 #![crate_type = "lib"] // 内部属性适用于整个函数。 fn some_unused_variables() { #![allow(unused_variables)] let x = (); let y = (); let z = (); } }
外部属性,写在哈希符号后不带感叹号,适用于属性后面的形式。
例子
#![allow(unused)] fn main() { // 标记为单元测试的函数 #[test] fn test_foo() { /* ... */ } // 有条件编译的模块 #[cfg(target_os = "linux")] mod bar { /* ... */ } // 用于抑制警告/错误的 lint 属性 #[allow(non_camel_case_types)] type int8_t = i8; }
属性由属性的路径组成,后跟一个可选的带分隔符的词法单元树,其解释由属性定义。除了宏属性之外,属性还允许输入是一个等号 (=) 后跟一个表达式。有关更多详细信息,请参阅下面的 元项属性语法。
属性的应用可能不安全。为避免在使用这些属性时出现未定义行为,必须满足某些编译器无法检查的义务。为了声明这些义务已满足,属性被 unsafe(..) 包裹,例如 #[unsafe(no_mangle)]。
以下属性是不安全的:
属性可以分为以下几种:
属性可以应用于语言中的多种形式:
- 所有 项声明 接受外部属性,而 外部块、函数、实现 和 模块 接受内部属性。
- 大多数 语句 接受外部属性(有关表达式语句的限制,请参阅 表达式属性)。
- 块表达式 接受外部和内部属性,但仅当它们是 表达式语句 的外部表达式或另一个块表达式的最终表达式时。
- 枚举 变体和 结构体 及 联合体 字段接受外部属性。
- 匹配表达式分支 接受外部属性。
- 泛型 生命周期或类型参数 接受外部属性。
- 表达式在有限情况下接受外部属性,详见 表达式属性。
- 函数、闭包 和 函数指针 参数接受外部属性。这包括在函数指针和 外部块 中用
...表示的可变参数上的属性。 - 内联汇编 模板字符串和操作数接受外部属性。语义上只接受某些属性;有关详细信息,请参阅 asm.attributes.supported-attributes。
元项属性语法
“元项”是大多数 内置属性 用于 Attr 规则的 语法格式。它具有以下语法:
Syntax
MetaItem →
SimplePath
| SimplePath = Expression
| SimplePath ( MetaSeq? )
MetaSeq →
MetaItemInner ( , MetaItemInner )* ,?
元项中的表达式必须宏展开为字面量表达式,其中不得包含整数或浮点类型后缀。非字面量表达式的表达式在语法上会被接受(并可传递给过程宏),但会在解析后被拒绝。
请注意,如果属性出现在另一个宏中,它将在该外部宏之后展开。例如,以下代码将首先展开 Serialize 过程宏,该宏必须保留 include_str! 调用才能被展开:
#[derive(Serialize)]
struct Foo {
#[doc = include_str!("x.md")]
x: u32
}
此外,属性中的宏只会在应用于该 项 的所有其他属性之后展开:
#[macro_attr1] // 首先展开
#[doc = mac!()] // `mac!` 第四次展开。
#[macro_attr2] // 第二次展开
#[derive(MacroDerive1, MacroDerive2)] // 第三次展开
fn foo() {}
各种内置属性使用元项语法的不同子集来指定它们的输入。以下语法规则展示了一些常用形式:
Syntax
MetaWord →
IDENTIFIER
MetaNameValueStr →
IDENTIFIER = ( STRING_LITERAL | RAW_STRING_LITERAL )
MetaListPaths →
IDENTIFIER ( ( SimplePath ( , SimplePath )* ,? )? )
MetaListIdents →
IDENTIFIER ( ( IDENTIFIER ( , IDENTIFIER )* ,? )? )
MetaListNameValueStr →
IDENTIFIER ( ( MetaNameValueStr ( , MetaNameValueStr )* ,? )? )
一些元项的示例如下:
| 样式 | 示例 |
|---|---|
| 元字 | no_std |
| 元名称值字符串 | doc = "example" |
| 元列表路径 | allow(unused, clippy::inline_always) |
| 元列表标识符 | macro_use(foo, bar) |
| 元列表名称值字符串 | link(name = "CoreFoundation", kind = "framework") |
活跃属性和惰性属性
属性要么是活跃的,要么是惰性的。在属性处理期间,活跃属性 会从它们所在的表单中移除自己,而 惰性属性 则保留在表单上。
cfg 和 cfg_attr 属性是活跃的。属性宏 是活跃的。所有其他属性都是惰性的。
工具属性
编译器可能允许外部工具的属性,其中每个工具都位于 工具预导入 中的自己的模块中。属性路径的第一个段是工具的名称,带有一个或多个额外段,其解释由工具决定。
当工具未使用时,工具的属性会被接受,而不会发出警告。当工具在使用时,工具负责处理和解释其属性。
如果使用了 no_implicit_prelude 属性,则工具属性不可用。
#![allow(unused)]
fn main() {
// 告诉 rustfmt 工具不要格式化以下元素。
#[rustfmt::skip]
struct S {
}
// 控制 clippy 工具的“圈复杂度”阈值。
#[clippy::cyclomatic_complexity = "100"]
pub fn f() {}
}
注意
rustc目前识别的工具包括 “clippy”, “rustfmt”, “diagnostic”, “miri” 和 “rust_analyzer”。
内置属性索引
以下是所有内置属性的索引。
-
条件编译
-
测试
test— 将函数标记为测试。ignore— 禁用测试函数。should_panic— 表示测试应生成一个 恐慌。
-
派生
derive— 自动 特型 实现。automatically_derived—derive创建的实现的标记。
-
宏
macro_export— 导出用于跨 crate 使用的macro_rules宏。macro_use— 扩展宏可见性,或从其他 crate 导入宏。proc_macro— 定义函数式宏。proc_macro_derive— 定义派生宏。proc_macro_attribute— 定义属性宏。
-
诊断
allow、expect、warn、deny、forbid— 更改默认 lint 级别。deprecated— 生成弃用通知。must_use— 对未使用的值生成 lint。diagnostic::on_unimplemented— 提示编译器在 未实现 特型 时发出特定错误消息。diagnostic::do_not_recommend— 提示编译器不要在错误消息中显示某个 特型 实现。
-
ABI、链接、符号和 FFI
link— 指定要与extern块链接的本地库。link_name— 指定extern块中函数或静态变量的符号名称。link_ordinal— 指定extern块中函数或静态变量的符号序号。no_link— 阻止链接外部 crate。repr— 控制类型布局。crate_type— 指定 crate 的类型(库、可执行文件等)。no_main— 禁用发出main符号。export_name— 指定函数或静态变量的导出符号名称。link_section— 指定函数或静态变量要使用的对象文件节。no_mangle— 禁用符号名称编码。used— 强制编译器将静态 项 保留在输出对象文件中。crate_name— 指定 crate 名称。
-
代码生成
inline— 提示内联代码。cold— 提示函数不太可能被调用。naked— 阻止编译器发出函数序言和尾声。no_builtins— 禁用使用某些内置函数。target_feature— 配置特定于平台的代码生成。track_caller— 将父调用位置传递给std::panic::Location::caller()。instruction_set— 指定用于生成函数代码的指令集。
-
文档
doc— 指定文档。有关更多信息,请参阅 The Rustdoc Book。 文档注释 会转换为doc属性。
-
预导入
no_std— 从 预导入 中移除 std。no_implicit_prelude— 禁用模块内的 预导入 查找。
-
模块
path— 指定模块的文件名。
-
限制
recursion_limit— 设置某些编译时操作的最大递归限制。type_length_limit— 设置多态类型的最大大小。
-
运行时
panic_handler— 设置处理 恐慌 的函数。global_allocator— 设置全局内存分配器。windows_subsystem— 指定要链接的 Windows 子系统。
-
特性
feature— 用于启用不稳定或实验性编译器 特性。有关rustc中实现的 特性,请参阅 The Unstable Book。
-
类型系统
non_exhaustive— 指示将来会为类型添加更多字段/变体。
-
调试器
debugger_visualizer— 嵌入一个文件,该文件指定某种类型的调试器输出。collapse_debuginfo— 控制宏调用在调试信息中编码的方式。