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);
            }
            _ => {}
        }
    }
}

后记

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

相关推荐
xinhuanjieyi2 分钟前
Android 画板应用kotlin实现
android·开发语言·kotlin
threelab6 分钟前
Three.js 几何图形变换 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器
无限进步_8 分钟前
Linux进程等待——wait、waitpid与僵尸进程
linux·运维·服务器·开发语言
野生技术架构师11 分钟前
Java 23 种设计模式:从踩坑到精通 —— 开篇及系列介绍
java·开发语言·设计模式
Wang ruoxi12 分钟前
Pygame 小游戏——数独
开发语言·python·pygame
人道领域18 分钟前
【LeetCode刷题日记】90.子集Ⅱ--- 归纳题解
java·开发语言·leetcode
ch.ju24 分钟前
Java Programming Chapter 4——Characteristics of inheritance
java·开发语言
复园电子25 分钟前
企业PDF批量盖章开发集成指南:API对接OA/LIMS系统,高并发落地实战
开发语言·python·pdf
SunnyDays101130 分钟前
如何使用 C# 自动调整 Excel 行高和列宽
开发语言·c#·excel
a诠释淡然43 分钟前
C++模板元编程—现代C++的黑魔法
开发语言·c++