返回介绍

10.2 宏

发布于 2024-10-13 11:25:32 字数 2913 浏览 0 评论 0 收藏 0

宏是一种元编程技术,用代码生成代码。

  • 直接展开(expand)到调用处。
  • 生成代码,灵活性非泛型可比。
  • 缺点是不便于调试。
macro_rules! name {
  (pattern1) => (template1);
  (pattern2) => (template2);
  ...
}
macro_rules! say_hello {
  () => (
    println!("Hello!");
  );
}

fn main() {
  say_hello!();  // 也可写成 say_hello![] 或 say_hello!{}。
}

添加参数,并标注其类型。

参数以 $ 为前缀, ident 表明类型是标识符,比如函数或变量名。

macro_rules! say_hello {
  ($s: ident) => (
    println!("hello, {}!", $s);
  );
}

fn main() {
  let s = "world!";
  say_hello!(s);
}
macro_rules! create_add {
  ($name: ident, $type: ty) => (
    fn $name(x: $type, y: $type) -> $type {
      x + y
    }
  );
}

create_add!(add1, i32);
create_add!(add2, f32);

fn main() {
  add1(1, 2);
  add2(1.1, 1.2);
}

像 match 那样,分支匹配。

macro_rules! test {
  ($one: expr) => (
    println!("{:?}", $one);
  );
  ($one: expr, $two: expr) => (
    println!("{:?}, {:?}", $one, $two);
  );
}

fn main() {
  test!(1 + 1);
  test!(1 + 1, 2);
}

接受变参,递归展开。

macro_rules! test {
  ($one: expr) => (
    println!("{:?}", $one);
  );
  ($one: expr, $($two: expr),+) => (  // + 表示 1 到多个。
    test!{ $one }           // 递归调用,用大括号。
    test!{ $($two),+ }
  );
}

fn main() {
  test!(1 + 1);
  test!(1 + 2, 4, 3 * 4);
}

内置宏

由编译器提供。

  • file! , line! , column!
  • cfg!
  • env!

导入导出

宏在编译前期被展开。

  • 模块中的宏,对子模块可见。可直接以名称调用,无需全路径。
// main.rs

macro_rules! say_hello {
  () => (
    println!("Hello!");
  );
}

pub mod a {
  pub mod b {
    pub fn test() {
      say_hello!();  // 子模块可见 !!!
    }
  }
}

fn main() {
  a::b::test();
}
  • 使用 #[macro_use] mod ,将子模块内的宏导出到当前模块。
// util.rs

macro_rules! elapsed {        // 无需 pub !!!
  ($e: expr) => (
    use std::time::Instant;
    let now = Instant::now();
    { $e; }
    println!("elapsed: {:?}", now.elapsed());
  );
}
// main.rs

#[macro_use] mod util;  // 导出 util 内的宏,无需额外 use 导入。

fn main() {
  elapsed!({
    println!("hello, world!");
  });
}
  • 使用 #[macro_export] 标记宏,自动导出到根模块。
// util.rs

#[macro_export]
macro_rules! elapsed {       // 无需 pub !!!
  ($e: expr) => (
    use std::time::Instant;
    let now = Instant::now();
    { $e; }
    println!("elapsed: {:?}", now.elapsed());
  );
}
// main.rs

mod util;

fn main() {
  elapsed!({
    println!("hello, world!");
  });
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文