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