本質上,宏是讓編譯器為您編寫代碼的工具。可以把宏當成一個公式,編譯器基于這個公式,用于在給定一些輸入參數的情況下生成代碼,編譯器會將宏的每次調用替換為運行該公式的結果。因此您可以將宏視為自動代碼替換,您可以在其中定義替換規則。Rust 的宏有許多不同的形狀和大小,可以輕松實現許多不同形式的代碼生成。
兩種主要類型是_聲明宏_和_過程宏_, 熟練 C/C++ 的程序員可能已經習慣了 C 和 C++ 宏的惡心地方,比如你可以無所限制地使用 #define 將每個 true 更改為 0 或 1 的值,因此在不同的源文件中 true 和 false 的值可能產生混亂。另外,通常情況下,C/C++的宏并沒有強制要求使用{}
來包含宏中的代碼段,因此也可能在一些if-else
邏輯中宏代碼可能被潛在的被分割或失效。甚至宏中的局部變量可能會對全局中的變量產生影響,弄臟使用環境。基于這些情況,就要求程序員連接宏的缺陷,使用規范的編程來避免宏的調用產生潛在的風險。
#define true 1
#define true 0
#define MAX(a, b) a > b? a: b
// 變量意外被修改多次
MAX(a1++, b1++)
#define INC(a, b) a++;b++
// 宏被分割了
if (true)
INC(a, b)
Rust 中的宏與 C/C++ 宏的則有相似又有提升,能更加干凈、安全得使用。以 Rust 聲明宏為例,常用的println!
就是聲明宏。
/// # Examples
///
/// ```
/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// let local_variable = "some";
/// println!("format {local_variable} arguments");
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
() => {
$crate::print!("\n")
};
($($arg:tt)*) => {{
$crate::io::_print($crate::format_args_nl!($($arg)*));
}};
}
Rust 的聲明宏與 C/C++的#define 功能類似,但是更加先進。Rust的聲明宏支持匹配多個模板,根據匹配結果選擇不同的替換邏輯。同時匹配的過程中,不會污染宏外的環境,使用也非常靈活高效。