属性
语法
内部属性 :
#
!
[
属性]
外围属性 :
#
[
属性]
属性 :
简单路径 属性输入?
属性 语法形式更加通用和自由,具体的所表达的语义,根据名称、约定及编译器版本解释。 rust 属性以 ECMA-335 中的属性为模型,其语法来自 ECMA-334 (C#) 。
内部属性 ,以井号 (#
) 后跟一个叹号 (!
) 形式声明,应用到包含它的条目内部。
外围属性 ,在井号后不加叹号,应用于随后的条目。
属性由一个路径和一个可选的定界符号 token 树组成,该 token 树的具体含义由属性解释。
除属性宏之外的属性还允许输入是一个等号 (=
) 后跟一个表达式。
参阅下面的 元项语法 。
属性有 4 种:
属性可以应用于语言中的许多内容:
- 所有的 条目声明 都接受外围属性,而 外部块 、 函数 、 实现 和 模块 接受内部属性。
- 大多数 语句 都接受外围属性 (关于表达式语句的限制,见 表达式属性 ) 。
- 块表达式 可以接受外围和内部属性,但是只有是 表达式语句 的外部表达式或另一个块表达式的最终表达式时。
- 枚举 变体和 结构体 和 联合体 字段接受外围属性。
- 匹配表达式分支 接受外围属性。
- 泛型生命周期或类型参数 接受外围属性。
- 表达式在有限的情况下接受外围属性,详见 表达式属性 。
- 函数 、 闭包 和 函数指针 参数接受外围属性。这包括在函数指针和 外部块 中用
...
表示的变量参数的属性。
一些属性的例子:
#![allow(unused)] fn main() { // 应用于顶层模块或 crate 。 #![crate_type = "lib"] // 标记为单元测试的函数 #[test] fn test_foo() { /* ... */ } // 条件编译模块 #[cfg(target_os = "linux")] mod bar { /* ... */ } // 用于屏蔽警告/错误的代码分析 #[allow(non_camel_case_types)] type int8_t = i8; // 整个函数的内部属性 fn some_unused_variables() { #![allow(unused_variables)] let x = (); let y = (); let z = (); } }
元项属性语法
"元项" 是大多数 内置属性 规则的语法,具体如下:
语法
元项 :
简单路径
| 简单路径=
表达式
| 简单路径(
元?)
元 :
元项内部 (,
元项内部 )*,
?元项内部 :
元项
| 表达式
元项中的表达式必须能够被宏展开字面值表达式,不得包含整数或浮点类型后缀。 非字面值表达式将在语法分析后被拒绝,但过程宏没有这一限制。
请注意,另一个宏中的属性,在该外部宏展开之后再展开。
例如,以下代码将首先扩展 Serialize
过程宏,展开后如果保留了 include_str!
,那么其随后展开:
#[derive(Serialize)]
struct Foo {
#[doc = include_str!("x.md")]
x: u32
}
此外,条目的所有属性展开之后,属性所包含的宏才会展开:
#[macro_attr1] // 首先展开
#[doc = mac!()] // `mac!` 第4展开 。这里的 doc 属性不会主动展开
#[macro_attr2] // 第二展开
#[derive(MacroDerive1, MacroDerive2)] // 第三展开
fn foo() {}
各种内置属性所使用的元项语法会有所不同。 以下是一些常用形式:
语法
元字:
标识符元名称值字符串:
标识符=
(字符串字面值 | 原始字符串字面值)元列表路径:
标识符(
( 简单路径 (,
简单路径)*,
? )?)
元列表ID组:
标识符(
( 标识符 (,
标识符)*,
? )?)
元列表名称值字符串:
标识符(
( 元名称值字符串 (,
元名称值字符串)*,
? )?)
一些例子:
类型 | 示例 |
---|---|
元字 | no_std |
元名称值字符串 | doc = "example" |
元列表路径组 | allow(unused, clippy::inline_always) |
元列表ID组 | macro_use(foo, bar) |
元列表名称值字符串 | link(name = "CoreFoundation", kind = "framework") |
活动和惰性属性
属性会是活动的或惰性的。对属性进行解释后 活动属性 会被移除,而 惰性属性 会被保留。
cfg
和 cfg_attr
属性是活动属性。 test
属性在测试编译时是惰性的,而在其他情况下是活动的。
属性宏 是活动属性。所有其他属性都是惰性的。
工具属性
编译器也接收外部工具的属性,在 tool prelude 命名空间中。 属性路径的第一个部分是工具的名称,后面可能有一个或多个其他部分,其含义由工具解释。
当一个工具没有被使用时,允许工具属性且不会产生警告。 当该工具正在使用时,该工具需要负责处理和解释其属性。
工具属性在启用 no_implicit_prelude
属性后不可用。
#![allow(unused)] fn main() { // 告知 rustfmt 工具不要格式化以下元素。 #[rustfmt::skip] struct S { } // 控制 Clippy 工具的 "cyclomatic complexity" 阈值。 #[clippy::cyclomatic_complexity = "100"] pub fn f() {} }
注意:
rustc
目前可以识别 "clippy" 和 "rustfmt" 两个工具。
内置属性索引
以下是所有内置属性的索引。
- 条件编译
- 测试
test
— 标记为测试函数ignore
— 禁用测试函数should_panic
— 表示测试应产生恐慌
- 衍生
derive
— 自动 trait 实现automatically_derived
— 由derive
创建的实现的标记
- 宏
macro_export
— 导出一个macro_rules
宏,用于跨 crate 使用。macro_use
— 扩展宏的可见性,或从其他 crate 导入宏。proc_macro
— 定义函数式宏。proc_macro_derive
— 定义衍生宏。proc_macro_attribute
— 定义属性宏。
- 诊断
- ABI, linking, symbols, and 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
— 提示函数不太可能被调用。no_builtins
— 禁止使用某些内置函数。target_feature
— 配置特定平台的代码生成。track_caller
- 将父级调用位置传递给std::panic::Location::caller()
。instruction_set
- 指定用于生成函数代码的指令集
- 文档
doc
— 用于指定文档。请参见 Rustdoc 文档 获取更多信息。 文档注释 会被转换为doc
属性。
- 预导入
no_std
— 从预导入中删除 std 。no_implicit_prelude
— 禁用模块内的预导入查询。
- 模块
path
— 指定模块的文件名。
- 范围
recursion_limit
— 设置某些编译时操作的最大递归限制。type_length_limit
— 设置多态类型的最大规模。
- 运行时
panic_handler
— 设定处理恐慌的函数。global_allocator
— 设置全局内存分配器。windows_subsystem
— 指定要链接的 windows 子系统。
- 特性
feature
— 用于启用未稳定或实验性的编译器特性。有关rustc
实现的特性,请参见 未稳定性文档 。
- 类型系统
non_exhaustive
— 表示该类型在未来可能会添加更多的字段/变体。