如何按需生成evalexpr上下文以匹配自定义结构体规则?
解决evalexpr处理大结构体仅转换规则用到字段的方案
先解析表达式提取目标字段
利用evalexpr的AST解析能力,先对用户编写的规则表达式做静态分析,提取其中引用的所有字段名。通过evalexpr::build_operator_tree生成抽象语法树后,递归遍历AST节点收集所有标识符(即结构体字段),这样就能精准定位规则用到的字段,不用处理全部60个。动态生成精简版上下文
基于提取到的字段名,通过反射工具(比如serde或reflectcrate)从CustomStruct实例中动态取出对应字段的值,转换为evalexpr兼容的Value类型后,再放入HashMapContext。示例代码如下:use evalexpr::{Value, HashMapContext}; use serde::Serialize; use std::collections::HashMap; #[derive(Serialize)] struct CustomStruct { // 模拟60个字段 field_x: i32, field_y: f64, nested_field: NestedStruct, // ...其他字段 } #[derive(Serialize)] struct NestedStruct { sub_field: String, } // 解析表达式提取字段名 fn extract_used_fields(expr: &str) -> Vec<String> { let tree = evalexpr::build_operator_tree(expr).unwrap(); let mut fields = Vec::new(); // 递归遍历AST收集标识符 fn traverse(node: &evalexpr::Node, fields: &mut Vec<String>) { match node { evalexpr::Node::Identifier(id) => fields.push(id.to_string()), evalexpr::Node::Operator(_, children) => { for child in children { traverse(child, fields); } } _ => {} } } traverse(&tree, &mut fields); fields.dedup(); fields } // 构建仅包含目标字段的上下文 fn build_target_context(inst: &CustomStruct, fields: &[String]) -> HashMapContext { let mut context = HashMapContext::new(); // 用serde将结构体转为通用JSON对象,按需提取字段 let obj = serde_json::to_value(inst).unwrap().as_object().unwrap(); for field in fields { if let Some(val) = obj.get(field) { let eval_val = Value::from_json(val).unwrap(); context.set_value(field.clone(), eval_val).unwrap(); } } context }适配复杂类型转换
针对嵌套结构体、枚举等复杂类型,提前定义好对应的Value转换逻辑——比如嵌套结构体转为Value::Object,枚举转为字符串或数值表示,确保evalexpr能正确解析这些类型的字段值。缓存优化性能
若同一条规则会重复执行,缓存提取到的字段名列表,避免每次都重新解析表达式,减少不必要的开销。
内容的提问来源于stack exchange,提问作者JoL
相关产品推荐
相关产品推荐

