iT邦幫忙

2024 iThome 鐵人賽

DAY 12
1
Software Development

Rust 學得動嗎系列 第 12

[Day 12] Rust 的進階模式匹配與Macro System

  • 分享至 

  • xImage
  •  

今天,我們來學習 Rust 的進階模式匹配技巧和Macro System。這些特性能大幅提升程式碼的表達能力和重用性。

1. 進階模式匹配(Advanced Pattern Matching)

模式匹配是 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);
    }
}

https://ithelp.ithome.com.tw/upload/images/20240926/20140358YrmbaYGhPf.png

使用 @ 綁定

#[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));
}

https://ithelp.ithome.com.tw/upload/images/20240926/201403583ugvtBjvjl.png

2. Macro系統(Macro System)

Rust 的Macro系統允許我們以元程式設計的方式生成程式碼,大大提高程式碼的重用性。

聲明式Macros(Declarative Macros)

使用 macro_rules! 定義聲明式Macros:

macro_rules! say_hello {
    // () => 表示Macros不接受任何參數
    () => {
        // Macros將被展開成這裡的程式碼
        println!("Hello!");
    };
}

fn main() {
    say_hello!();
}

https://ithelp.ithome.com.tw/upload/images/20240926/20140358n7UMYSddbY.png

接受參數的Macro

macro_rules! create_function {
    // 此Macro接受一個 ident 作為參數
    ($func_name:ident) => {
        fn $func_name() {
            println!("你呼叫了 {}", stringify!($func_name));
        }
    };
}

create_function!(foo);

fn main() {
    foo();
}

https://ithelp.ithome.com.tw/upload/images/20240926/20140358Zwn4WQsrRW.png

程序式Macros(Procedural Macros)

程序式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()
}

實際應用範例:建立一個簡單的領域特定語言(DSL)

讓我們使用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);
}

https://ithelp.ithome.com.tw/upload/images/20240926/20140358Mv1E8yFXQW.png


上一篇
[Day 11] Rust 的模組系統、套件管理與測試
下一篇
[Day 13] Rust 在系統程式設計中的應用
系列文
Rust 學得動嗎30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言