属性
语法
内部属性 :
#![属性]外围属性 :
#[属性]属性 :
简单路径 属性输入?
属性 语法形式更加通用和自由,具体的所表达的语义,根据名称、约定及编译器版本解释。 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— 表示该类型在未来可能会添加更多的字段/变体。