教程

巨集允許我們抽象多次重複的語法模式。例如:

/// Computes `a + b * c`. If any of the operation overflows, returns `None`.
fn checked_fma(a: u64, b: u64, c: u64) -> Option<u64> {
    let product = match b.checked_mul(c) {
        Some(p) => p,
        None => return None,
    };
    let sum = match a.checked_add(product) {
        Some(s) => s,
        None => return None,
    };
    Some(sum)
}

我們注意到兩個 match 語句非常相似:它們都具有相同的模式

match expression {
    Some(x) => x,
    None => return None,
}

想象一下,我們將上面的模式表示為 try_opt!(expression),然後我們可以將函式重寫為 3 行:

fn checked_fma(a: u64, b: u64, c: u64) -> Option<u64> {
    let product = try_opt!(b.checked_mul(c));
    let sum = try_opt!(a.checked_add(product));
    Some(sum)
}

try_opt! 無法編寫函式,因為函式不支援早期返回。但我們可以用巨集來做 - 只要我們有這些無法使用函式表示的語法模式,我們就可以嘗試使用巨集。

我們使用 macro_rules! 語法定義一個巨集:

macro_rules! try_opt {
//                  ^ note: no `!` after the macro name
    ($e:expr) => {
//   ^~~~~~~ The macro accepts an "expression" argument, which we call `$e`.
//           All macro parameters must be named like `$xxxxx`, to distinguish from
//           normal tokens.
        match $e {
//            ^~ The input is used here.
            Some(x) => x,
            None => return None,
        }
    }
}

而已! 我們建立了第一個巨集。

(在 Rust Playground 嘗試 )