属性

attributes.md
commit: eabdf09207bf3563ae96db9d576de0758c413d5d
本章译文最后维护日期:2021-1-24

句法
InnerAttribute :
   # ! [ Attr ]

OuterAttribute :
   # [ Attr ]

Attr :
   SimplePath AttrInput?

AttrInput :
      DelimTokenTree
   | = LiteralExpression不带后缀

属性是一种通用的、格式自由的元数据(free-form metadatum),这种元数据会(被编译器/解释器)依据名称、约定、语言和编译器版本进行解释。(Rust 语言中的)属性是根据 ECMA-335 标准中的属性规范进行建模的,其语法来自 ECMA-334 (C#)。

*内部属性(Inner attributes)*以 #! 开头的方式编写,应用于它在其中声明的程序项。*外部属性(Outer attributes)*以不后跟感叹号的(!)的 # 开头的方式编写,应用于属性后面的内容。

属性由指向属性的路径和路径后跟的可选的带定界符的 token树(delimited token tree)(其解释由属性定义)组成。除了宏属性之外,其他属性的输入也允许使用等号(=)后跟文字表达式的格式。更多细节请参见下面的元项属性句法(meta item syntax)

属性可以分为以下几类:

属性可以应用于语言中的许多场景:

属性的一些例子:

#![allow(unused)]
fn main() {
// 应用于当前模块或 crate 的一般性元数据。
#![crate_type = "lib"]

// 标记为单元测试的函数
#[test]
fn test_foo() {
    /* ... */
}

// 一个条件编译模块
#[cfg(target_os = "linux")]
mod bar {
    /* ... */
}

// 用于静音 lint检查后报告的告警和错误提醒
#[allow(non_camel_case_types)]
type int8_t = i8;

// 适用于整个函数的内部属性
fn some_unused_variables() {
  #![allow(unused_variables)]

  let x = ();
  let y = ();
  let z = ();
}
}

元项/元程序项属性句法

“元项(meta item)”是遵循 Attr 产生式(见本章头部)的句法,Rust 的大多数内置属性(built-in attributes)都使用了此句法。它有以下文法格式:

句法
MetaItem :
      SimplePath
   | SimplePath = LiteralExpression不带后缀
   | SimplePath ( MetaSeq? )

MetaSeq :
   MetaItemInner ( , MetaItemInner )* ,?

MetaItemInner :
      MetaItem
   | LiteralExpression不带后缀

元项中的字面量表达式不能包含整型或浮点类型的后缀。

各种内置属性使用元项句法的不同子集来指定它们的输入。下面的文法规则展示了一些常用的使用形式:

句法
MetaWord:
   IDENTIFIER

MetaNameValueStr:
   IDENTIFIER = (STRING_LITERAL | RAW_STRING_LITERAL)

MetaListPaths:
   IDENTIFIER ( ( SimplePath (, SimplePath)* ,? )? )

MetaListIdents:
   IDENTIFIER ( ( IDENTIFIER (, IDENTIFIER)* ,? )? )

MetaListNameValueStr:
   IDENTIFIER ( ( MetaNameValueStr (, MetaNameValueStr)* ,? )? )

元项句法的一些例子是:

形式示例
MetaWordno_std
MetaNameValueStrdoc = "example"
MetaListPathsallow(unused, clippy::inline_always)
MetaListIdentsmacro_use(foo, bar)
MetaListNameValueStrlink(name = "CoreFoundation", kind = "framework")

活跃属性和惰性属性

属性要么是活跃的,要么是惰性的。在属性处理过程中,活跃属性将自己从它们所在的对象上移除,而惰性属性依然保持原位置不变。

cfgcfg_attr 属性是活跃的。test属性在为测试所做的编译形式中是惰性的,在其他编译形式中是活跃的。宏属性是活跃的。所有其他属性都是惰性的。

外部工具属性

编译器可能允许和具体外部工具相关联的属性,但这些工具在编译和检查过程中必须存在并驻留在编译器提供的工具类预导入包下对应的命名空间中(才能让这些属性生效)。这种属性的(命名空间)路径的第一段是工具的名称,后跟一个或多个工具自己解释的附加段。

当工具在编译期不可用时,该工具的属性将被静默接受而不提示警告。当工具可用时,该工具负责处理和解释这些属性。

如果使用了 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”。

内置属性的索引表

下面是所有内置属性的索引表:

  • 条件编译(Conditional compilation)
    • cfg — 控制条件编译。
    • cfg_attr — 选择性包含属性。
  • 测试(Testing)
    • test — 将函数标记为测试函数。
    • ignore — 禁止测试此函数。
    • should_panic — 表示测试应该产生 panic。
  • 派生(Derive)
  • 宏(Macros)
  • 诊断(Diagnostics)
  • ABI、链接(linking)、符号(symbol)、和 FFI
    • link — 指定要与外部(extern)块链接的本地库。
    • link_name — 指定外部(extern)块中的函数或静态项的符号(symbol)名。
    • no_link — 防止链接外部crate。
    • repr — 控制类型的布局。
    • crate_type — 指定 crate 的类别(库、可执行文件等)。
    • no_main — 禁止发布 main符号(symbol)。
    • export_name — 指定函数或静态项导出的符号(symbol)名。
    • link_section — 指定用于函数或静态项的对象文件的部分。
    • no_mangle — 禁用对符号(symbol)名编码。
    • used — 强制编译器在输出对象文件中保留静态项。
    • crate_name — 指定 crate名。
  • 代码生成(Code generation)
    • inline — 内联代码提示。
    • cold — 提示函数不太可能被调用。
    • no_builtins — 禁用某些内置函数。
    • target_feature — 配置特定于平台的代码生成。
    • track_caller - 将父调用位置传递给 std::panic::Location::caller()
  • 文档(Documentation)
  • 预导入包(Preludes)
  • 模块(Modules)
    • path — 指定模块的源文件名。
  • 极限值设置(Limits)
    • recursion_limit — 设置某些编译时操作的最大递归限制。
    • type_length_limit — 设置多态类型(polymorphic type)单态化过程中构造具体类型时所做的最大类型替换次数。
  • 运行时(Runtime)
  • 特性(Features)
    • feature — 用于启用非稳定的或实验性的编译器特性。参见 The Unstable Book 了解在 rustc 中实现的特性。
  • 类型系统(Type System)
    • non_exhaustive — 表明一个类型将来会添加更多的字段/变体。