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

后记

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

相关推荐
大卫小东(Sheldon)1 小时前
写了一个BBP算法的实现库,欢迎讨论
数学·rust
侃侃_天下6 小时前
最终的信号类
开发语言·c++·算法
echoarts7 小时前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Aomnitrix7 小时前
知识管理新范式——cpolar+Wiki.js打造企业级分布式知识库
开发语言·javascript·分布式
每天回答3个问题8 小时前
UE5C++编译遇到MSB3073
开发语言·c++·ue5
伍哥的传说8 小时前
Vite Plugin PWA – 零配置构建现代渐进式Web应用
开发语言·前端·javascript·web app·pwa·service worker·workbox
小莞尔8 小时前
【51单片机】【protues仿真】 基于51单片机八路抢答器系统
c语言·开发语言·单片机·嵌入式硬件·51单片机
我是菜鸟0713号9 小时前
Qt 中 OPC UA 通讯实战
开发语言·qt
JCBP_9 小时前
QT(4)
开发语言·汇编·c++·qt·算法
Brookty9 小时前
【JavaEE】线程安全-内存可见性、指令全排序
java·开发语言·后端·java-ee·线程安全·内存可见性·指令重排序