Rust Tutorial


Example

Macros allow us to abstract syntactical patterns that are repeated many times. For instance:

/// 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)
}

We notice that the two match statements are very similar: both of them have the same pattern

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

Imagine we represent the above pattern as try_opt!(expression), then we could rewrite the function into just 3 lines:

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! cannot write a function because a function does not support the early return. But we could do it with a macro — whenever we have these syntactical patterns that cannot be represented using a function, we may try to use a macro.

We define a macro using the macro_rules! syntax:

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,
        }
    }
}

That's it! We have created our first macro.

(Try it in Rust Playground)