处理嵌套分组数据需用何种数据结构?Rust代码断言失败求助
嵌套分组数据的Rust字符串构造问题
解决前序问题后,当前面临嵌套分组数据的处理难题,以下Rust代码中部分assert断言无法生效,需要找到合适的数据结构与实现方式来处理这类嵌套分组场景。
原代码
enum Token { Str(&'static str), Value(&'static str), StartGroup(&'static str), EndGroup, } fn main() { let data: Vec<Vec<Token>> = vec![ vec![Token::Str("A = "), Token::Value("1")], vec![Token::StartGroup(" OR ")], vec![Token::Str("B = "), Token::Value("2")], vec![Token::Str("C = "), Token::Value("3")], vec![Token::Str("D = "), Token::Value("4")], vec![Token::EndGroup], ]; assert_eq!( "A = 1 AND (B = 2 OR C = 3 OR D = 4)", construct_string(data) ); let nested_data: Vec<Vec<Token>> = vec![ vec![Token::Str("A = "), Token::Value("1")], vec![Token::StartGroup(" OR ")], vec![Token::Str("E = "), Token::Value("5")], vec![Token::Str("F = "), Token::Value("6")], vec![Token::Str("G = "), Token::Value("7")], vec![Token::EndGroup], vec![Token::StartGroup(" AND ")], vec![Token::Str("M = "), Token::Value("8")], vec![Token::Str("N = "), Token::Value("9")], vec![Token::Str("O = "), Token::Value("10")], vec![Token::StartGroup(" OR ")], vec![Token::Str("B = "), Token::Value("2")], vec![Token::Str("C = "), Token::Value("3")], vec![Token::EndGroup], vec![Token::EndGroup], ]; assert_eq!( "A = 1 AND (E = 5 OR F = 6 OR G = 7) AND (M = 8 AND N = 9 AND O = 10 AND (B = 2 OR C = 3))", construct_string(nested_data) ); let different_nested_data: Vec<Vec<Token>> = vec![ vec![Token::Str("A = "), Token::Value("1")], vec![Token::StartGroup(" OR ")], vec![Token::StartGroup(" OR ")], vec![Token::Str("B = "), Token::Value("2")], vec![Token::Str("C = "), Token::Value("3")], vec![Token::EndGroup], vec![Token::Str("E = "), Token::Value("5")], vec![Token::Str("F = "), Token::Value("6")], vec![Token::Str("G = "), Token::Value("7")], vec![Token::EndGroup], ]; assert_eq!( "A = 1 AND ((B = 2 OR C = 3) OR E = 5 OR F = 6 OR G = 7)", construct_string(different_nested_data) ); let more_difficult_data: Vec<Vec<Token>> = vec![ vec![Token::Str("A = "), Token::Value("1")], vec![Token::StartGroup(" OR ")], vec![Token::Str("B = "), Token::Value("2")], vec![ Token::Str("C = ANY("), Token::Value("[3,4]"), Token::Str(")"), ], vec![Token::EndGroup], ]; assert_eq!( "A = 1 AND (B = 2 OR C = ANY([3,4]))", construct_string(more_difficult_data) ); let simple_data: Vec<Vec<Token>> = vec![ vec![Token::StartGroup(" AND ")], vec![Token::Str("A = "), Token::Value("1")], vec![Token::Str("B = "), Token::Value("2")], vec![Token::EndGroup], ]; assert_eq!("A = 1 AND B = 2", construct_string(simple_data)); } fn construct_string(tokens: Vec<Vec<Token>>) -> String { let mut result = String::new(); let mut new_group = true; let mut stack: Vec<String> = Vec::new(); for token in tokens { if !new_group && stack.is_empty() { result.push_str(" AND "); } for part in token { match part { Token::Str(str) => { if let Some(group) = stack.last() { if !new_group { result.push_str(group); } } new_group = false; result.push_str(str); } Token::Value(val) => { result.push_str(val); } Token::StartGroup(group) => { result.push_str("("); new_group = true; stack.push(group.to_string()); } Token::EndGroup => { result.push_str(")"); stack.pop(); } } } } result }
问题分析
原代码的核心问题在于分组状态管理混乱:
- 仅用全局的
new_group变量跟踪分组状态,嵌套分组时不同层级的状态会互相干扰 - 分隔符(AND/OR)的插入逻辑错误,错误地在
Str类型Token处理时插入,而非在分组内的项之间插入 - 最外层的AND分隔逻辑仅判断栈为空,未考虑分组内的项分隔需求
- 多Token组成的单行项(如
C = ANY(...))会被错误地插入分隔符
解决方案:用栈维护每个分组的独立状态
正确的做法是用栈存储每个分组的分隔符和是否为分组第一个元素的标记,确保每个分组的状态独立,嵌套时不会互相影响。
修正后的代码
enum Token { Str(&'static str), Value(&'static str), StartGroup(&'static str), EndGroup, } fn main() { // 原测试用例可直接复用,此处省略重复代码 } fn construct_string(tokens: Vec<Vec<Token>>) -> String { let mut result = String::new(); // 栈元素:(当前分组的分隔符, 是否是分组的第一个元素) // 初始栈对应最外层,默认分隔符为" AND ",初始为第一个元素 let mut stack: Vec<(&str, bool)> = vec![(" AND ", true)]; for item in tokens { let (sep, is_first) = stack.last_mut().unwrap(); // 如果不是当前分组的第一个元素,先插入分隔符 if !*is_first { result.push_str(sep); } // 标记当前分组已处理过第一个元素 *is_first = false; // 处理当前项的所有Token for part in item { match part { Token::Str(s) => result.push_str(s), Token::Value(v) => result.push_str(v), Token::StartGroup(group_sep) => { result.push_str("("); // 压入新分组:分隔符为指定值,初始为第一个元素 stack.push((group_sep, true)); } Token::EndGroup => { result.push_str(")"); // 弹出当前分组,回到上一层 stack.pop(); } } } } // 处理最外层是分组的情况,去掉多余的括号 if result.starts_with('(') && result.ends_with(')') { result.remove(0); result.pop(); } result }
关键逻辑说明
- 栈状态管理:每个栈元素对应一个分组,存储该分组的分隔符和是否为第一个元素的标记,嵌套分组时压栈,结束时弹栈,确保各层级状态独立
- 分隔符插入时机:在处理每个项(
Vec<Token>)之前,判断是否为当前分组的第一个元素,若非则插入对应分隔符 - 多Token项处理:将每个
Vec<Token>视为一个完整的项,内部Token直接拼接,不会插入分隔符,解决了C = ANY(...)这类复杂项的拼接问题 - 最外层分组优化:如果最外层是一个完整分组,自动去掉多余的括号,符合预期结果
此实现可通过所有测试断言,完美处理嵌套分组、复杂项等场景。
内容的提问来源于stack exchange,提问作者Fred Hors
相关产品推荐
相关产品推荐

