首页 > 编程语言 > 详细

[易学易懂系列|rustlang语言|零基础|快速入门|(22)|宏Macro]

时间:2019-12-15 19:29:42      阅读:89      评论:0      收藏:0      [点我收藏+]

[易学易懂系列|rustlang语言|零基础|快速入门|(22)|宏Macro]

实用知识

宏Macro

我们今天来讲讲Rust中强大的宏Macro。

Rust的宏macro是实现元编程的强大工具。

宏主要作用为:

1.减少重复代码。

2.编写DSL(Domain-specific languages。

3.可变参数接口定义。

我们来看看简单的宏定义:

// 宏名字为:`say_hello`.
macro_rules! say_hello {
    // `()` 这里括号里没有任何表达式,表示这个宏不用接受任何参数.
    () => {
        // 宏将把上面的括号()内的表达式展开到这个大括号{}中的代码。
        println!("Hello!");
    };
}

fn main() {
    // 调用这个宏,将直接把这个宏展开为代码: `println!("Hello");`
    say_hello!()
}

我们再来看看稍微有点复杂的宏定义:

macro_rules! create_function {
    // 这个宏定义有两个参数:ident为标识符,主要用来标识变量或函数,表明宏展开为变量或函数;
    //而$func_name则为宏代码中代码展开的参数名,这里为函数名.
    ($func_name:ident) => {
        fn $func_name() {
            //这里的宏 `stringify!`直接把函数名字转换成字符串。
            println!("You called {:?}()", stringify!($func_name));
        }
    };
}

macro_rules! print_result {
    //这个宏把一个表达式,并把表达式的字符串和表达式结果一起打印出来。 
    //而标识符expr,主要用来标识表达式。
    ($expression:expr) => {
        // `stringify!` 宏将把表达式转换成字符串形式
        println!("{:?} = {:?}", stringify!($expression), $expression);
    };
}

fn main() {
    // 用上面的宏create_function!分别创建foo和bar函数
    create_function!(foo);
    create_function!(bar);

    foo();//调用foo函数,即调用代码:println!("You called {:?}()", stringify!(foo));
    bar();/调用foo函数,即调用代码:println!("You called {:?}()", stringify!(bar));
    
//用上面宏print_result!,将把代码展开为:
//println!("{:?} = {:?}", stringify!(1u32 + 1), 1u32 + 1);
    print_result!(1u32 + 1);

    // 同样,将大括号的代码当成表达式参数传给上面的宏print_result!
    print_result!({
        let x = 1u32;

        x * x + 2 * x - 1
    });
}

运行上面的代码,打印结果为:

You called "foo"()
You called "bar"()
"1u32 + 1" = 2
"{ let x = 1u32; x * x + 2 * x - 1 }" = 2

我们从上面的代码来一一分析,一般来说宏定义用:macro_rules! 开头,表明这是个宏。

基本形式为:() => { };

其中小括号为宏定义的参数:主要用来定义宏的参数,其中参数有个标识符,主要用来表明宏定义的表达式展开的参数类型。

有以下标识符:

  • block 代码块BlockExpression
  • expr 用于表达式
  • ident用于变量或函数名
  • item 元素 Item
  • literal 用于常量
  • pat (pattern) 用于模式匹配
  • path  用于路径
  • stmt (statement) 用于声明
  • tt (token tree) 用于语法树
  • ty (type)   用于类型
  • vis (visibility qualifier) 用于访问权限控制

代码重载

宏可以像模式匹配一样,可以根据参数不同,匹配不同的宏定义代码,如下例子:

/ `test!` 宏主要用来比较 `$left` 和 `$right`
// 它会根据你调用时的参数自动匹配不一样的代码:
macro_rules! test {
    // 参数之间不一定要用逗号隔开
    // 任何形式的模板代码都可以
    ($left:expr; and $right:expr) => {
        println!("{:?} and {:?} is {:?}",
                 stringify!($left),
                 stringify!($right),
                 $left && $right)
    };
    // 每个left参数必须以分号结尾
    ($left:expr; or $right:expr) => {
        println!("{:?} or {:?} is {:?}",
                 stringify!($left),
                 stringify!($right),
                 $left || $right)
    };
}

fn main() {
    test!(1i32 + 1 == 2i32; and 2i32 * 2 == 4i32);
    test!(true; or false);
}

运行上面代码,结果为:

"1i32 + 1 == 2i32" and "2i32 * 2 == 4i32" is true
"true" or "false" is true

重复调用

宏定义可以用加号+来表示,可以传入一个或多个参数;同样,也可以星号*来表示可以传入零个或多个参数。

我们看看简单例子:

// `min!` 宏主要用来求多个表达式结果中的最小值.
macro_rules! find_min {
    //一个参数的情况:
    ($x:expr) => ($x);
    // 参数`$x` 和至少一个参数 `$y,`的情况
    ($x:expr, $($y:expr),+) => (
        // 调用标准库中的最小值求值函数 ,并且让`find_min!`作用于参数  `$y`和更多其它参数
        std::cmp::min($x, find_min!($($y),+))
    )
}

fn main() {
    println!("{}", find_min!(1u32));
    println!("{}", find_min!(1u32 + 2, 2u32));
    println!("{}", find_min!(5u32, 2u32 * 3, 4u32));
}

运行结果:

1
2
4

以上,希望对你有用。

如果遇到什么问题,欢迎加入:rust新手群,在这里我可以提供一些简单的帮助,加微信:360369487,注明:博客园+rust

参考文章:

https://doc.rust-lang.org/stable/rust-by-example/macros.html

https://danielkeep.github.io/tlborm/book/index.html

[易学易懂系列|rustlang语言|零基础|快速入门|(22)|宏Macro]

原文:https://www.cnblogs.com/gyc567/p/12045350.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!