【Rust每週一知】 Attribute 屬性
原創 Mike Tang Rust語言中文社區 3天前
屬性是作用在 Rust 語言元素上的元數據。
Rust 中的屬性數量非常多。而且具有可擴展性(可自定義屬性)。Rust 的屬性語法遵從 C# 定義並標準化了的屬性規範ECMA-334。
Rust 代碼中隨處可見屬性,有時甚至會多得讓人摸不着頭腦。本篇是對 Rust 中的屬性相關知識的簡單總結。水平有限,僅起到拋磚引玉的作用。
概念
整體來講,屬性還是比較好理解的,但是需要先理解一些基本概念:
Inner Attributes(內部屬性) 和 Outer Attributes(外部屬性)
內部屬性(Inner Attribute)是指:一個屬性聲明在一個元素中,對此元素(比如一般爲 crate)整體生效。內部屬性用 #![] 聲明。
外部屬性(Outer Attribute)是指:一個屬性聲明在一個元素之前,對跟在後面的這個元素生效。外部屬性用 #[] 聲明。
Rust 中,有些屬性可以/只能作內部屬性使用,有些屬性可以/只能作外部屬性使用。
Meta Item Attribute Syntax
Meta Item Attribute Syntax 實際上描述了屬性語法的基本結構。
下面表格羅列了所有 Meta Item Attribute Syntax。第一列是語法樣式名稱,第二列是語法看起來的樣子。
我們在 Rust 代碼中看到的所有屬性語法都是上述五種中的一種或其組合。
Active 和 insert 屬性
一個屬性,要麼是 active 的,要麼是 insert 的。
Active 屬性是指,在處理屬性(預處理代碼)的過程中,active 屬性會將它們自己刪除,留下所作用的元素。
Insert 屬性是指,在處理屬性(預處理代碼)的過程中,insert 屬性會將它們自己保留。
cfg 和 cfg_attr 屬性是 active 的。
當編譯爲 test 模式時,test 屬性是 insert 的。編譯爲非 test 模式時,test 屬性是 active 的。
屬性宏是 active 的。
所有其它屬性是 insert 的。
屬性的分類
Rust 中的屬性,可以分爲以下四大類。
Macro attributes - 宏屬性
Derive macro helper attributes - 派生宏輔助屬性
Tool attributes - 工具屬性
Built-in attributes - 內建屬性
Macro Attributes 宏屬性
宏屬性,也叫屬性宏。屬於過程宏的一種。
定義過程宏的時候,使用 #[proc_macro_attribute],加一個固定簽名的函數(詳見過程宏一章)。
#[proc_macro_attribute]
pub fn return_as_is(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
使用過程宏:
#[return_as_is]
fn invoke() {}
Derive macro helper attributes 派生宏輔助屬性
派生宏輔助屬性,聽起來有點拗口,其實它是這樣一個東西:
先定義派生宏
#[proc_macro_derive(HelperAttr, attributes(helper))]
pub fn derive_helper_attr(_item: TokenStream) -> TokenStream {
TokenStream::new()
}
看如何使用:
#[derive(HelperAttr)]
struct Struct {
#[helper] field: ()
}
裏面那個 #[helper] 就是一個派生宏輔助屬性。
Tool Attributes 工具屬性
工具屬性。Rust 還允許外部工具定義它們自己的屬性,並且在獨立的命名空間下面。比如:
// 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() {}
不過如果你想在自己的工具中定義 Tool Attribute,那就想多了。現在 rustc 只認識兩個外部工具(及它們內部的屬性):一個是 rustfmt,另一個是 clippy。
Built-in Attributes 內建屬性
4 種屬性的前面兩種:宏屬性和派生宏輔助屬性,是可以完全自定義的。後面兩種:工具屬性和內建屬性,我們只能用,不能自定義。
Rust 內建了 14 類屬性。OMG @_@!!
每一個屬性都有自己的用法,有的用法還比較多,可以用到的時候,再去查閱。這裏簡單羅列說明一下。
條件編譯
cfg
cfg_attr
測試
test
ignore
should_panic
派生
derive
宏相關
macro_export
macro_use
proc_macro
proc_macro_derive
proc_macro_attribute
診斷
allow, warn, deny, forbid - lint 相關標誌開關,各種 lint 見附錄。
deprecated
must_use
ABI, 鏈接, 符號, 和 FFI
link
link_name
no_link
repr
crate_type
no_main
export_name
link_section
no_mangle
used
crate_name
代碼生成
inline
cold
no_builtins
target_feature
文檔
doc
預引入
no_std
no_implicit_prelude
模塊
path
限制
recursion_limit
type_length_limit
運行時
panic_handler
global_allocator
windows_subsystem
語言特性
feature - 經常會碰到這裏面一些陌生的 feature 名稱,需要根據具體的 rustc 版本和所使用的庫文檔進行查閱。
類型系統
non_exhaustive
上面的屬性中,很多屬性,其內容都可以單獨開一篇文章來講解。比如,條件編譯相關的屬性,FFI 相關屬性等。
參考
本文內容主要來自:https://doc.rust-lang.org/reference/attributes.html。 加入了作者的一些理解。各位同學有時間的話,最好將上述文檔中的內容每一個都仔細過一遍。這樣,需要用到的時候,溫習一下就會用了。也並不是太難的事兒。
Unstable Book 對 rustc 的 flags 和各種 features 都做了詳細的說明。