rust编译、元编程

本文详细介绍了Rust语言中的宏系统,包括宏的分类(声明宏、过程宏),声明宏的匹配语法、范畴、调用方式,以及多参数匹配和常见声明宏如println!和assert_eq!的示例。特别提到了声明宏的卫生性,以及函数宏、属性宏和派生宏的区别。
摘要由CSDN通过智能技术生成

目录

〇,编译过程

一,宏的分类

二,声明宏

1,声明宏的匹配语法

2,匹配范畴

3,声明宏的调用

4,多入参匹配

5,常见声明宏

6,声明宏的卫生性

三,函数宏

四,属性宏

五,派生宏


〇,编译过程

在c和c++中,只需要知道宏是编译之前的预处理就行了。

但是rust中的宏更强大,也更为复杂,而且和编译过程有更为紧密的联系。

rust有13种token,包括表达式、语句、标识符等等,即下面的声明宏的匹配范畴。

一,宏的分类

rust的宏分为声明宏、过程宏。

过程宏又分为函数宏、属性宏、派生宏

二,声明宏

1,声明宏的匹配语法

声明宏的作用类似于代码替换,匹配语法和match很像。

macro_rules! my_show {
    () => {
        println!("run to here");
    };
    ($sth:expr)=>{
        println!("run to here {}", $sth);
    }
}

fn gcd(x:i32, y:i32) ->i32{
    if y < 0 {
        my_show!(y);
        return gcd(-x,-y);
    }
    if y == 0 {
        my_show!();
        return x;
    }
    return gcd(y, x%y);
}
 
fn main() {
    gcd(15,-18);
    println!("{:#?}",5);
}

2,匹配范畴

上面的$sth:expr表示匹配到一个表达式,expr是表示表达式这个范畴。

  • item:语言项。比如一个函数、结构体、模块等
  • block:代码块。比如一系列由花括号包裹的表达式和语句
  • stmt:语句。比如一个赋值语句
  • pat:模式
  • expr:表达式。
  • ty:类型。比如 Vec
  • ident:标识符。比如一个变量名
  • path:路径。比如:foo、::std::mem::replacetransmute::<_, int>
  • meta:元数据。一般是在 #[...] 和 #![...] 属性内部的数据
  • tt:单个的 token 树
  • vis:可能为空的一个 Visibility 修饰符。比如 pub、pub(crate)
  • literal :字面量
  • lifetime :生命周期

3,声明宏的调用

!()也可以 ![]也可以 !{}也可以

4,多入参匹配

macro_rules! my_vec {
    () => {
        Vec::new();
    };
    ($x:expr;$n:expr,$($y:expr),*)=>({
        let mut v = Vec::new();
        for i in 0..$n {
            v.push($x);
        }
        $(v.push($y);)*
        v
    });
}
 
fn main() {
    let v:Vec<i32> = my_vec!();
    assert_eq!(v.len(), 0);
    let v = my_vec!(1;6,2,3,4);
    assert_eq!(v, Vec::from([1,1,1,1,1,1,2,3,4]));
    println!("end");
}

这里其实相当于是传了3个参数,1和6之间用;连接, 6和“2,3,4”之间有逗号连接,用什么连接取决于宏的匹配格式里面写的是什么。

而2,3,4匹配的是$($y:expr),*这个类似正则表达式的东西,表示可以匹配任意多个表达式,用,连接起来

5,常见声明宏

println:

macro_rules! println {
    () => {
        $crate::print!("\n")
    };
    ($($arg:tt)*) => {{
        $crate::io::_print($crate::format_args_nl!($($arg)*));
    }};
}

assert_eq:

macro_rules! assert_eq {
    ($left:expr, $right:expr $(,)?) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = $crate::panicking::AssertKind::Eq;
                    // The reborrows below are intentional. Without them, the stack slot for the
                    // borrow is initialized even before the values are compared, leading to a
                    // noticeable slow down.
                    $crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::None);
                }
            }
        }
    };
    ($left:expr, $right:expr, $($arg:tt)+) => {
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    let kind = $crate::panicking::AssertKind::Eq;
                    // The reborrows below are intentional. Without them, the stack slot for the
                    // borrow is initialized even before the values are compared, leading to a
                    // noticeable slow down.
                    $crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::Some($crate::format_args!($($arg)+)));
                }
            }
        }
    };
}

6,声明宏的卫生性

声明宏是半卫生宏,变量标识符不会造成符号冲突,符合卫生性。

但是在宏内部定义的泛型和生命周期标识符是不卫生的。

三,函数宏

四,属性宏

五,派生宏

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值