属性
语法
内部属性 :
#
!
[
Attr]
外部属性 :
#
[
Attr]
Attr :
SimplePath AttrInput?
|unsafe
(
SimplePath AttrInput?)
AttrInput :
DelimTokenTree
|=
Expression
属性是一种通用的、自由形式的元数据,其解释取决于名称、约定、语言和编译器版本。属性以 ECMA-335 中的属性为模型,语法来自 ECMA-334 (C#)。
内部属性,在哈希符号 (#
) 后写一个感叹号 (!
),应用于声明属性的项目内部。外部属性,在哈希符号后不写感叹号,应用于属性之后的项目。
属性由属性的路径组成,后跟一个可选的带分隔符的 token 树,其解释由属性定义。宏属性以外的属性也允许输入为等号 (=
) 后跟一个表达式。有关更多详细信息,请参阅下面的 元项语法。
应用属性可能是不安全的。为了避免使用这些属性时出现未定义的行为,必须满足某些编译器无法检查的义务。为了声明已经满足这些义务,属性被包裹在 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
| SimplePath=
Expression
| SimplePath(
MetaSeq?)
MetaSeq :
MetaItemInner (,
MetaItemInner )*,
?MetaItemInner :
MetaItem
| Expression
元项中的表达式必须宏展开为字面量表达式,字面量表达式不得包含整数或浮点类型后缀。非字面量表达式将在语法上被接受(并且可以传递给过程宏),但将在解析后被拒绝。
请注意,如果属性出现在另一个宏中,它将在外部宏之后展开。例如,以下代码将首先展开 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:
IDENTIFIERMetaNameValueStr:
IDENTIFIER=
(STRING_LITERAL | RAW_STRING_LITERAL)MetaListPaths:
IDENTIFIER(
( SimplePath (,
SimplePath)*,
? )?)
MetaListIdents:
IDENTIFIER(
( IDENTIFIER (,
IDENTIFIER)*,
? )?)
MetaListNameValueStr:
IDENTIFIER(
( MetaNameValueStr (,
MetaNameValueStr)*,
? )?)
元项的一些示例包括
样式 | 示例 |
---|---|
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
属性是活动的。test
属性在为测试编译时是惰性的,否则是活动的。属性宏 是活动的。所有其他属性都是惰性的。
工具属性
编译器可能允许外部工具的属性,其中每个工具都位于 工具 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
— 定义一个派生宏。proc_macro_attribute
— 定义一个属性宏。
-
诊断
allow
,expect
,warn
,deny
,forbid
— 更改默认的 lint 级别。deprecated
— 生成弃用通知。must_use
— 为未使用的值生成 lint。diagnostic::on_unimplemented
— 提示编译器在 trait 未实现时发出特定的错误消息。diagnostic::do_not_recommend
— 提示编译器不要在错误消息中显示特定的 trait 实现。
-
ABI、链接、符号和 FFI
link
— 指定要与extern
块链接的本机库。link_name
— 指定extern
块中函数或静态变量的符号名称。link_ordinal
— 指定extern
块中函数或静态变量的符号序号。no_link
— 阻止链接外部 crate。repr
— 控制类型布局。crate_type
— 指定 crate 的类型(库、可执行文件等)。no_main
— 禁用发出main
符号。export_name
— 指定函数或静态变量的导出符号名称。link_section
— 指定对象文件中用于函数或静态变量的 section。no_mangle
— 禁用符号名称编码。used
— 强制编译器在输出对象文件中保留静态项。crate_name
— 指定 crate 名称。
-
代码生成
inline
— 内联代码提示。cold
— 函数不太可能被调用的提示。no_builtins
— 禁用某些内置函数的使用。target_feature
— 配置特定于平台的代码生成。track_caller
— 将父调用位置传递给std::panic::Location::caller()
。instruction_set
— 指定用于生成函数代码的指令集
-
文档
doc
— 指定文档。有关更多信息,请参阅 The Rustdoc Book。文档注释 将转换为doc
属性。
-
Preludes
no_std
— 从 prelude 中删除 std。no_implicit_prelude
— 禁用模块内的 prelude 查找。
-
模块
path
— 指定模块的文件名。
-
限制
recursion_limit
— 设置某些编译时操作的最大递归限制。type_length_limit
— 设置多态类型的最大大小。
-
运行时
panic_handler
— 设置处理 panic 的函数。global_allocator
— 设置全局内存分配器。windows_subsystem
— 指定要链接的 windows 子系统。
-
特性
feature
— 用于启用不稳定或实验性编译器特性。有关rustc
中实现的特性,请参阅 The Unstable Book。
-
类型系统
non_exhaustive
— 表示类型将在未来添加更多字段/变体。
-
调试器
debugger_visualizer
— 嵌入一个文件,该文件指定类型的调试器输出。collapse_debuginfo
— 控制宏调用如何在 debuginfo 中编码。