Rust macro 笔记

真正意义上的宏编程起源于 lisp,rust 把 lisp 从头到脚借鉴了一通,所以宏也逃不了。

lisp 中宏可以定义 lisp 自身代码,大大简化 lisp 编写工作,rust 同理。

rust 与 lisp 类似,都是基于表达式的语法,所以宏在某种意义上也是表达式。当然,这里的宏比 C 的宏高级许多。

宏定义宏

macro_rules! puts {
    ($string: expr) => (print!("{}n", $string));
}

puts!("Printed by macro.") // -> echo 'Printed by macro.n'

macro_rules! println_xy {
    (x => $e: expr) => (println!("x: {}", $e));
    (y => $e: expr) => (println!("y: {}", $e));
}

println_xy!(x => 5);  // -> echo 'x: 5n'
println_xy!(y => 6);  // -> echo 'y: 6n'

宏生成函数

macro_rules! create_fn {
    ($function_name: ident) => (
        fn $function_name() {
            println!("function '{}' created by macro", stringify!($function_name));
        }
    );
}

create_fn!(my_fun);
my_fun()  // -> echo "function 'my_fun' created by macro"

重载宏

// overload
macro_rules! arithmetic {
    ($e1: expr ,+ $e2: expr) => ($e1 + $e2);
    ($e1: expr ,- $e2: expr) => ($e1 - $e2);
    ($e1: expr ,* $e2: expr) => ($e1 * $e2);
    ($e1: expr ,/ $e2: expr) => ($e1 / $e2);
}

arithmetic!(2 ,+ 4)  // -> 6
arithmetic!(2 ,- 4)  // -> -2
arithmetic!(2 ,* 4)  // -> 8
arithmetic!(2 ,/ 4)  // -> 0

通配


// wildcard 1
macro_rules! vec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

vec! {32, 25}  // -> [32, 25]

// wildcard 2
use std::collections::HashMap;

macro_rules! hash {
    ( $( $key: expr => $val: expr),+ ) => {
        {
            let mut hash = HashMap::new();

            $(
                hash.insert($key, $val);
            )*

            hash
        }
    };
}

hash! {
    "Joe"   => 32,
    "David" => 25
}  // -> {"David": 25, "Joe": 32}

宏还可以进行许多高级操作,比如递归等等。学海无涯,这些还需要查询相关资料和文档。

宏需要在编译时提前展开,展开后方可执行。

参考:

  1. TRPL – Macro
  2. Rust By Example – Macro

作者: YanWen

Web 开发者

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

You are commenting using your WordPress.com account. Log Out /  更改 )

Google photo

You are commenting using your Google account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

Connecting to %s