上海免费网站建站模板,长沙模板网站建设,云主机免费,.net网站空间本人rust萌新#xff0c;写web碰到了这个#xff0c;基于ChatGPT和文心一言学了宏#xff0c;强行把这玩意实现出来了#xff0c;做个学习记录#xff0c;如果有更好的方法#xff0c;勿喷。
先看效果#xff0c;注意不支持嵌套#xff0c;且kv映射要用(因为它这个…本人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,key3String::from(value)
);//第一个变量没了就是默认空msg后面的全部存入data{key1:...,key2:...}
success!(keyqwer,key21324,
);fail!同理
rust中实现统一返回类有点麻烦比如我想返回固定格式
{success:true,msg:登录成功,data:{id:15,name:qwer}
}我目前用的是actix-web虽然支持直接传入结构体对象作为json返回值但我有时候想对于data进行灵活的处理不想建那么多结构体
这里我基于serde_json的json!进行进一步封装 这里一个宏里面写两个形式因为要匹配传入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:HashMapString,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:HashMapString,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:HashMapString,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:HashMapString,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() - JsonValue {let resp success!(success,key1 vec![1,2,3,4,5],key2 qwer,key3String::from(value));resp
}我理解的这个宏就是字符串替换因为他是编译阶段处理的所以宏所在rs文件的use是无效的即使用了宏的文件需要对于宏使用的第三方库进行use这个有点恶心问题不大。