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

后记

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

相关推荐
SomeB1oody1 小时前
【RustyML入门】5.0. 模型评估
开发语言·后端·机器学习·rust·教程
Evand J1 小时前
【MATLAB例程,PDR11】二维平面下的PDR(行人航位推算)步态检测与EKF融合定位,附代码的下载链接
开发语言·matlab·平面·pdr·行人导航·步态检测
牛油果子哥q1 小时前
C++STL算法超全精讲:排序/查找/去重/遍历/最值/合并全套API、仿函数、Lambda适配、实战避坑
开发语言·c++·算法
Xeon_CC2 小时前
用C++编写屏幕准星
开发语言·c++
孤存5222 小时前
c语言动态内存管理
c语言·开发语言·算法
冰暮流星2 小时前
javascript之webstorage用法
开发语言·javascript·ecmascript
我一定会有钱2 小时前
打造完美工作流:Git 配置”一次推送,三端同步”(Gitee/GitCode/GitHub)
开发语言·windows·vscode·搜索引擎·gitlab·github·visual studio code
matlab代码2 小时前
基于matlab肤色人脸标记检测系统 GUI界面【源码53期】
开发语言·matlab·人脸标记
KhalilRuan2 小时前
UnityCsReference——笔记
java·开发语言·笔记
电子云与长程纠缠2 小时前
UE5 Lyra PocketWorld进行3D内容UI预览 - 上
开发语言·学习·3d·ue5·游戏引擎