一种基于宏和serde_json实现的rust web中统一返回类

本人rust萌新,写web碰到了这个,基于ChatGPT和文心一言学了宏,强行把这玩意实现出来了,做个学习记录,如果有更好的方法,勿喷。

先看效果,注意不支持嵌套,且kv映射要用=>(因为它这个只支持用箭头),即在这个宏语法内只支持单层kv,但是你可以传value为HashMap。
对此我曾尝试用#[proc_macro]TokenStream拿到变量名和值的方式实现正常使用花括号和冒号和深层字典,但是太菜了搞不会。
如果能基于我的想法实现出深层kv,欢迎评论区分享。

//第一个变量是msg,后面的全部存入data{key1:...,key2:...}
success!(
   "success",
    "key1"=> vec![1,2,3,4,5],
    "key2" =>"qwer",
    "key3"=>String::from("value")
);

在这里插入图片描述

//第一个变量没了就是默认空msg,后面的全部存入data{key1:...,key2:...}
success!(
 	"key"=>"qwer",
    "key2"=>1324,
);

在这里插入图片描述
fail!同理

rust中实现统一返回类有点麻烦,比如我想返回固定格式

{
	"success":true,
	"msg":"登录成功",
	"data":{
		"id":15,
		"name":"qwer"
	}
}

我目前用的是actix-web,虽然支持直接传入结构体对象作为json返回值,但我有时候想对于data进行灵活的处理,不想建那么多结构体

这里我基于serde_jsonjson!进行进一步封装
这里一个宏里面写两个形式,因为要匹配传入msg和不传入msg的两种情形。最后一个$(,)?是允许最后一个多余的逗号,换行时好看一点

// 随便找个文件放
// 用了#[macro_export]的宏会直接放在crate下

//下面三个库需要在使用下面宏的地方进行use,此处use没用
// use actix_web::web;
// use serde_json::json;
// use std::collections::HashMap;

#[macro_export]
macro_rules! success {
    // 没有msg的情况
    ($($key:expr => $value:expr),* $(,)?) => {
        {
            let mut resp = HashMap::new();
            resp.insert("success", json!(true));
            resp.insert("msg", json!("")); // 提供一个默认的消息
            let mut data:HashMap<String,Value> = HashMap::new();
            $(
                data.insert($key, json!($value));
            )*
            resp.insert("data",json!(data));
            web::Json(json!(resp))
        }
    };
    // 有msg的情况
    ($msg:expr,  $($key:expr => $value:expr),* $(,)?) => {
       {
            let mut resp = HashMap::new();
            resp.insert("success", json!(true));
            resp.insert("msg", json!($msg)); // 提供一个默认的消息
            let mut data:HashMap<String,Value> = HashMap::new();
            $(
                data.insert($key, json!($value));
            )*
            resp.insert("data",json!(data));
            web::Json(json!(resp))
        }
    };
}

#[macro_export]
macro_rules! fail {
    // 没有$msg的情况
    ($($key:expr => $value:expr),* $(,)?) => {
        {
            let mut resp = HashMap::new();
            resp.insert("success", json!(false));
            resp.insert("msg", json!(""));
            let mut data:HashMap<String,Value> = HashMap::new();
            $(
                data.insert($key, json!($value));
            )*
            resp.insert("data",data);
            web::Json(json!(resp))
        }
    };
    // 有$msg的情况
    ($msg:expr,  $($key:expr => $value:expr),* $(,)?) => {
       {
            let mut resp = HashMap::new();
            resp.insert("success", json!(false));
            resp.insert("msg", json!($msg));
            let mut data:HashMap<String,Value> = HashMap::new();
            $(
                data.insert($key, json!($value));
            )*
            resp.insert("data",json!(data));
            web::Json(json!(resp))
        }
    };
}

注意:过程宏需要定义在一个单独的crate中,主要是因为过程宏是一段在编译crate前,对其代码进行加工的代码,而这段是需要在编译后执行的。若是将定义过程宏和使用过程宏放到同一个crate中,就会陷入编译“死锁”:

另一个文件对其进行调用

// 注意是在crate下面的
use crate::success;
use actix_web::{
    get,web::{self, Json},
};
use serde_json::{json, Value};
use std::collections::HashMap;

#[get("/login")]
async fn login() -> Json<Value> {
    let resp = success!(
        "success",
        "key1"=> vec![1,2,3,4,5],
        "key2" =>"qwer",
        "key3"=>String::from("value")
    );
    resp
}

我理解的这个宏就是字符串替换,因为他是编译阶段处理的,所以宏所在rs文件的use是无效的,即使用了宏的文件需要对于宏使用的第三方库进行use,这个有点恶心,问题不大。

相关推荐

  1. 75.实现统一异常处理封装统一返回结果

    2024-03-12 08:56:06       32 阅读
  2. Springboot 设置统一返回格式

    2024-03-12 08:56:06       32 阅读
  3. springboot优雅实现异常拦截返回统一结构数据

    2024-03-12 08:56:06       34 阅读
  4. C# 基于 event 委托事件机制

    2024-03-12 08:56:06       10 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-12 08:56:06       14 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-12 08:56:06       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-12 08:56:06       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-12 08:56:06       18 阅读

热门阅读

  1. 简单谈谈DNS服务器的响应策略和筛选机制

    2024-03-12 08:56:06       18 阅读
  2. [python3] 责任链模式

    2024-03-12 08:56:06       17 阅读
  3. spring activiti ACT_RE_MODEL

    2024-03-12 08:56:06       15 阅读
  4. SpringController返回值和异常自动包装

    2024-03-12 08:56:06       17 阅读
  5. jsp中${xxx}代表什么

    2024-03-12 08:56:06       16 阅读
  6. h5唤起微信小程序

    2024-03-12 08:56:06       18 阅读
  7. 【基于arm linux c语言编程MODBUS rs485 RTU模式】

    2024-03-12 08:56:06       19 阅读
  8. django动态表技术(根据日期,年月日)方法一

    2024-03-12 08:56:06       21 阅读