今天,我們來學習 Rust 的進階模式匹配技巧和Macro System。這些特性能大幅提升程式碼的表達能力和重用性。
模式匹配是 Rust 中非常強大的功能,可以用在許多地方,不僅僅是 match
表達式。
struct Point {
x: i32,
y: i32,
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
println!("x = {}, y = {}", x, y);
let msg = Message::Move { x: 3, y: -1 };
if let Message::Move { x, y } = msg {
println!("移動到 ({}, {})", x, y);
}
}
@
綁定#[derive(Debug)]
struct Id(i32);
fn print_id(id: &Id) {
match id {
Id(n @ 1..=5) => println!("小 ID:{}", n),
Id(n @ 6..=10) => println!("中 ID:{}", n),
Id(n) => println!("大 ID:{}", n),
}
}
fn main() {
print_id(&Id(3));
print_id(&Id(8));
print_id(&Id(15));
}
Rust 的Macro系統允許我們以元程式設計的方式生成程式碼,大大提高程式碼的重用性。
使用 macro_rules!
定義聲明式Macros:
macro_rules! say_hello {
// () => 表示Macros不接受任何參數
() => {
// Macros將被展開成這裡的程式碼
println!("Hello!");
};
}
fn main() {
say_hello!();
}
macro_rules! create_function {
// 此Macro接受一個 ident 作為參數
($func_name:ident) => {
fn $func_name() {
println!("你呼叫了 {}", stringify!($func_name));
}
};
}
create_function!(foo);
fn main() {
foo();
}
程序式Macros允許你在編譯時運行程式碼來生成程式碼。以下是一個簡單的衍生Macro(Derive Macro)示例:
use proc_macro::TokenStream;
use quote::quote;
use syn;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// 將輸入解析為語法樹
let ast = syn::parse(input).unwrap();
// 建構特徵實現
impl_hello_macro(&ast)
}
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("你好,Macros!我的名字是 {}", stringify!(#name));
}
}
};
gen.into()
}
讓我們使用Macro來建立一個簡單的 SQL 查詢 DSL:
macro_rules! sql {
// SELECT 語句
(SELECT $($column:ident),+ FROM $table:ident) => {
format!("SELECT {} FROM {}", stringify!($($column),+), stringify!($table))
};
// SELECT 語句帶 WHERE 條件
(SELECT $($column:ident),+ FROM $table:ident WHERE $condition:expr) => {
format!("SELECT {} FROM {} WHERE {}",
stringify!($($column),+),
stringify!($table),
stringify!($condition)
)
};
// INSERT 語句
(INSERT INTO $table:ident ($($column:ident),+) VALUES ($($value:expr),+)) => {
format!("INSERT INTO {} ({}) VALUES ({})",
stringify!($table),
stringify!($($column),+),
stringify!($($value),+)
)
};
}
fn main() {
// 簡單的 SELECT 查詢
let query1 = sql!(SELECT name, age FROM users);
println!("Query 1: {}", query1);
// 帶 WHERE 條件的 SELECT 查詢
let query2 = sql!(SELECT id, email FROM customers WHERE age > 18);
println!("Query 2: {}", query2);
// INSERT 查詢
let query3 = sql!(INSERT INTO products (name, price) VALUES ("Apple", 0.5));
println!("Query 3: {}", query3);
}