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

后记

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

相关推荐
AI的魔盒2 分钟前
基于Java与MAVLink协议的多无人机(Cube飞控)集群控制与调度方案问题
java·开发语言·无人机
爱的叹息17 分钟前
解决 Dart Sass 的旧 JS API 弃用警告 的详细步骤和解决方案
javascript·rust·sass
一颗知足的心32 分钟前
Go语言之路————指针、结构体、方法
开发语言·后端·golang
yuanpan42 分钟前
C#如何正确的停止一个多线程Task?CancellationTokenSource 的用法。
开发语言·c#
程高兴44 分钟前
单相交直交变频电路设计——matlab仿真+4500字word报告
开发语言·matlab
我真的不会C1 小时前
QT中的事件及其属性
开发语言·qt
2501_906314322 小时前
优化无头浏览器流量:使用Puppeteer进行高效数据抓取的成本降低策略
开发语言·数据结构·数据仓库
让我们一起加油好吗3 小时前
【C++】类和对象(上)
开发语言·c++·visualstudio·面向对象
magic 2453 小时前
深入解析Promise:从基础原理到async/await实战
开发语言·前端·javascript
只因从未离去3 小时前
黑马Java基础笔记-4
java·开发语言·笔记