声明宏

Rust常用声明宏

println!

println!使用示例

#![allow(unused)]
fn main() {
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow_internal_unstable(print_internals, format_args_nl)]
macro_rules! println {
    () => ($crate::print!("\n"));
    ($($arg:tt)*) => ({
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    })
}
}

writeln!

可以将内容输入到指定文件

cargo run --example raw_command > examples/raw_command_output.txt

eprintln!

示例

声明宏示意图

声明宏定义使用流程图

声明宏定义使用流程1.[macro_export]macro_rules! my_vec {// 没带任何参数的 my_vec,我们创建一个空的 vec// 注意,由于宏要在调用的地方展开,我们无法预测调用// 者的环境是否已经 做了相关的 use,所以我们使用的// 代码最好带着完整的命名空间。() => {std::vec::Vec::new()};// 处理 my_vec![1, 2, 3, 4]($($el:expr),*) => ({let mut v = std::vec::Vec::new();$(v.push($el);)*v});// 处理 my_vec![0; 10]($el:expr; $n:expr) => {std::vec::from_elem($el, $n)}}定义声明宏fn main() {let mut v = my_vec![];v.push(1);// 调用时可以使用 [], (), {}let _v = my_vec!(1, 2, 3, 4);let _v = my_vec![1, 2, 3, 4];let v = my_vec! {1, 2, 3, 4};println!("{:?}", v); println!("{:?}", v);//let v = my_vec![1; 10];println!("{:?}", v);}使用声明宏

macro_rules!定义与使用

macro_rules!定义示例

#[macro_export]
macro_rules! my_vec {
    // 没带任何参数的 my_vec,我们创建一个空的 vec
    // 注意,由于宏要在调用的地方展开,我们无法预测调用
    // 者的环境是否已经 做了相关的 use,所以我们使用的
    // 代码最好带着完整的命名空间。
    () => {
        std::vec::Vec::new()
    };
    // 处理 my_vec![1, 2, 3, 4]
    ($($el:expr),*) => ({
        let mut v = std::vec::Vec::new();
        $(v.push($el);)*
        v
    });
    // 处理 my_vec![0; 10]
    ($el:expr; $n:expr) => {
        std::vec::from_elem($el, $n)
    }
}

$($el:expr), *)

  1. 在声明宏中,条件捕获的参数使用 $ 开头的标识符来声明。
  2. 每个参数都需要提供类型,这里expr代表表达式,所以 $el:expr 是说把匹配到的表达式命名为 $el。
  3. $(…),* 告诉编译器可以匹配任意多个以逗号分隔的表达式,然后捕获到的每一个表达式可以用 $el 来访问。
  4. 由于匹配的时候匹配到一个 $(…)* (我们可以不管分隔符),在执行的代码块中,我们也要相应地使用 $(…)* 展开。
  5. 所以这句 $(v.push($el);)* 相当于匹配出多少个 $el就展开多少句 push 语句。

macro_rules!使用示例

fn main() {
    let mut v = my_vec![];
    v.push(1);
    // 调用时可以使用 [], (), {}
    let _v = my_vec!(1, 2, 3, 4);
    let _v = my_vec![1, 2, 3, 4];
    let v = my_vec! {1, 2, 3, 4};
    println!("{:?}", v);

    println!("{:?}", v);
    //
    let v = my_vec![1; 10];
    println!("{:?}", v);
}

声明宏用到的参数类型

类型列表

  1. item,比如一个函数、结构体、模块等。
  2. block,代码块。比如一系列由花括号包裹的表达式和语句。
  3. stmt,语句。比如一个赋值语句。
  4. pat,模式。
  5. expr,表达式。刚才的例子使用过了。
  6. ty,类型。比如 Vec。
  7. ident,标识符。比如一个变量名。
  8. path,路径。比如:foo、::std::mem::replace、transmute::<_, int>。
  9. meta,元数据。一般是在 #[…] 和 #![…] 属性内部的数据。
  10. tt,单个的 token 树。
  11. vis,可能为空的一个 Visibility 修饰符。比如 pub、pub(crate)