教程

宏允许我们抽象多次重复的语法模式。例如:

/// 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 尝试 )