【Rust】類函數(shù)宏 | Rust宏入門
本筆記總結(jié)自
我對(duì)其中的案例有所簡(jiǎn)化
bilibili不支持markdown是真的難頂
概述
宏的種類
Attributes
內(nèi)置宏 built-in?
過(guò)程宏 proc-macro?
派生宏 derive
函數(shù)式的宏
AKA 類函數(shù)宏
macro_rules!
宏的變種,一般只考慮macro_rules!
這一個(gè)宏
宏展開(kāi)
很像 C 的 Define
,在編譯時(shí)自動(dòng)替換
rust 中的宏是在 AST 之后展開(kāi),自己會(huì)加括號(hào),不會(huì)改變運(yùn)算順序
衛(wèi)生性
hygiene 一個(gè)概念,簡(jiǎn)單理解為:宏不應(yīng)該隱式地改變或創(chuàng)建變量
比如一個(gè)宏,用戶沒(méi)有傳入變量a
,但它把a
的值改變了;或者它創(chuàng)建了變量b
,但始終沒(méi)有move或drop,就不衛(wèi)生
調(diào)試
rustc +nightly -Zunpretty=expanded hello.rs
思路
基本語(yǔ)法
expansion
也可以叫做 transcriber
matcher
匹配()
或胡言亂語(yǔ)
匹配元變量
該例中,matcher
為 $($elem: expr),*
元變量

有一個(gè)特殊的元變量叫做 $crate
,它用來(lái)指代當(dāng)前 crate 。
小例子:
反復(fù)
repetition
語(yǔ)法:
$(...) sep rep
其中:
$
: a token (token意為標(biāo)記)
(...)
: the matcher which need repetition
sep
: an optional separator token; example:,
;
rep
:?
appear zero or one time*
appear any times+
appear once or more
Example:
?
多個(gè)變量的情況:
macro metavariable expressions
Unstable now (2023.3.27) and we can not use it in a stable channel
實(shí)戰(zhàn)
斐波納切數(shù)列

構(gòu)建步驟
確定調(diào)用形式
確定想要生成的代碼
改善調(diào)用形式
初步構(gòu)建
替換
測(cè)試
導(dǎo)出
確定調(diào)用形式
據(jù)此,初步構(gòu)建宏:
依次匹配:
字面量:
a[n] =
一個(gè)及以上的表達(dá)式(expr)
字面量:
, ... ,
一個(gè)表達(dá)式(expr),本例中,此為通式
確定想要生成的代碼
?
改善調(diào)用形式
在 coding 的過(guò)程中發(fā)現(xiàn),用戶可能需要能夠自定義迭代器中Item
的類型
故修改宏的調(diào)用形式為:
據(jù)此初步構(gòu)建宏:
初步構(gòu)建
將前面幾個(gè)步驟的結(jié)果組合在一起
?
cargo test
?
這是由于在某次版本更新后, expr
之后只能跟隨 =>
、,
、;
之一
故解決方法為用 ;...;
代替 ,...,
,修改以下兩行:
當(dāng)前完整代碼:
?
替換
完成后:
?
cargo test
?
據(jù)說(shuō)在 nightly 版本中,可以變異通過(guò)。此處不通過(guò)的原因在于,測(cè)試中的 a
和 n
與宏中的 a
和 n
具有不同的上下文,解決方法是:
?
這樣,rustc 才能推斷出 a
和 n
是 ident
(identifier)
其他測(cè)試
?
導(dǎo)出宏
?
完整代碼
?