rust过程宏

前言

rust声明宏基本上就是直接简单的替换,类似于c的define。而过程宏则类似于java的注解编程。通过注解标签,标记生成特定的代码。

正文

但是因为过程宏可以生成代码。所以需要单独的模块。需要单独的crate。并且该crate必须标记用来处理过程宏。需要再cargo.tomal添加标签

argo 复制代码
[lib]
proc-macro = true
doctest = false

而大部分的模块需要提供函数:

rust 复制代码
#[proc_macro_derive(OBU_Parser, attributes(obu))]
#[proc_macro_error]
pub fn parser(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    //
    let token_stream = expand_filed(input);
    //
    token_stream
        .unwrap_or_else(|e| e.into_compile_error())
        .into()

    // TokenStream::new()
}

使用时候主要是:

java 复制代码
#[derive(OBU_Parser)]
struct color_info {
    #[obu(len = -3)]
    r: u8,
}

这里会把

rust 复制代码
struct color_info {
    r: u8,
}

转化成TokenStream,传给函数,然后最后生成TokenStream。替换原来的struct。

如何解析input的TokenStream,生成我们需要的TokenStream,下面我们写一些测试代码:

主要通过syn解析tokenstream

rust 复制代码
use quote::quote;
use syn::__private::ToTokens;
use syn::{parse_quote, File, Item};

extern crate quote;

struct X {
    x: i32,
}

fn main() {

    let code = quote! {
        struct X {
            x: Vec<i32>,
        }
    };

    let mut syntax_tree: File = syn::parse2(code).unwrap();


    syntax_tree.items = syntax_tree.items.into_iter().filter(|item| {
        matches!(item, Item::Struct(_))
    }).collect();

    for item in syntax_tree.items {
        match item {
            Item::Struct(item_fn) => {

                item_fn.fields.iter().for_each(|field| {

                    println!("file: {:?}", field);

                    match &field.ty{
                        syn::Type::Path(path) => {
                            println!("{:?}", path.path.segments[0].ident);

                            println!("arguments:{:?}", path.path.segments[0].arguments);

                            let ident = path.path.segments[0].ident.to_string();

                            if ident == "i32" {
                                println!("i32 field {:?}", field.ident);
                            }else if ident == "Vec" {
                                println!("Vec field {:?}", field.ident);
                            }
                        }
                        _ => {
                            println!("else {:?}", field.ty);
                        }
                    }
                });

                //将item_fn转换成原始代码字符串
                let code = quote! { #item_fn }.to_string();
                println!("{}", code);
                // fn_list.push(code);
            }
            _ => {}
        }
    }
}

后记

这里主要简要记录一下过程宏的。

相关推荐
Wish3D22 分钟前
阿里云OSS 上传文件 Python版本
开发语言·python·阿里云
凤年徐23 分钟前
【数据结构初阶】单链表
c语言·开发语言·数据结构·c++·经验分享·笔记·链表
oioihoii25 分钟前
C++11 右值引用:从入门到精通
开发语言·c++
朝新_3 小时前
【多线程初阶】阻塞队列 & 生产者消费者模型
java·开发语言·javaee
立莹Sir3 小时前
Calendar类日期设置进位问题
java·开发语言
风逸hhh4 小时前
python打卡day46@浙大疏锦行
开发语言·python
火兮明兮5 小时前
Python训练第四十三天
开发语言·python
ascarl20106 小时前
准确--k8s cgroup问题排查
java·开发语言
fpcc6 小时前
跟我学c++中级篇——理解类型推导和C++不同版本的支持
开发语言·c++
莱茵菜苗7 小时前
Python打卡训练营day46——2025.06.06
开发语言·python