属性

语法
内部属性 :
   # ! [ 属性 ]

外围属性 :
   # [ 属性 ]

属性 :
   简单路径 属性输入?

属性输入 :
      定界Token树
   | = 表达式

属性 语法形式更加通用和自由,具体的所表达的语义,根据名称、约定及编译器版本解释。 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")

活动和惰性属性

属性会是活动的或惰性的。对属性进行解释后 活动属性 会被移除,而 惰性属性 会被保留。

cfgcfg_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" 两个工具。

内置属性索引

以下是所有内置属性的索引。

  • 条件编译
    • cfg — 条件编译
    • cfg_attr — 条件展开属性
  • 测试
    • test — 标记为测试函数
    • ignore — 禁用测试函数
    • should_panic — 表示测试应产生恐慌
  • 衍生
  • 诊断
  • 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 - 指定用于生成函数代码的指令集
  • 文档
  • 预导入
  • 模块
    • path — 指定模块的文件名。
  • 范围
  • 运行时
  • 特性
    • feature — 用于启用未稳定或实验性的编译器特性。有关 rustc 实现的特性,请参见 未稳定性文档
  • 类型系统
    • non_exhaustive — 表示该类型在未来可能会添加更多的字段/变体。