如何简化Rust中AstNode枚举的Debug冗余实现代码?
简化枚举AstNode的Debug trait冗余实现
现有一个枚举AstNode<'a>,其所有变体都仅包含一个内部结构,当前手动实现的Debug trait代码非常冗余,每个分支都只是转发内部结构的fmt方法,如何简化这段代码?
原实现代码:
impl<'a> Debug for AstNode<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AstNode::Literal(inner) => inner.fmt(f), AstNode::Variable(inner) => inner.fmt(f), AstNode::Binary(inner) => inner.fmt(f), AstNode::Unary(inner) => inner.fmt(f), AstNode::Call(inner) => inner.fmt(f), AstNode::Function(inner) => inner.fmt(f), AstNode::If(inner) => inner.fmt(f), AstNode::While(inner) => inner.fmt(f), AstNode::Begin(inner) => inner.fmt(f), AstNode::Assign(inner) => inner.fmt(f), AstNode::NewGlobal(inner) => inner.fmt(f), AstNode::Error(inner) => inner.fmt(f), AstNode::TestAssert(inner) => inner.fmt(f), AstNode::TestExpect(inner) => inner.fmt(f), } } }
方案1:合并模式匹配分支
利用Rust模式匹配的多分支合并特性,将所有变体归到同一个分支下,直接缩短代码长度:
impl<'a> Debug for AstNode<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { AstNode::Literal(inner) | AstNode::Variable(inner) | AstNode::Binary(inner) | AstNode::Unary(inner) | AstNode::Call(inner) | AstNode::Function(inner) | AstNode::If(inner) | AstNode::While(inner) | AstNode::Begin(inner) | AstNode::Assign(inner) | AstNode::NewGlobal(inner) | AstNode::Error(inner) | AstNode::TestAssert(inner) | AstNode::TestExpect(inner) => inner.fmt(f), } } }
方案2:提取辅助方法集中处理
如果后续可能新增变体,可以先给AstNode实现一个辅助方法,专门获取内部结构的可调试引用,再在Debug实现中调用:
impl<'a> AstNode<'a> { fn inner_debug(&self) -> &dyn Debug { match self { AstNode::Literal(inner) => inner, AstNode::Variable(inner) => inner, AstNode::Binary(inner) => inner, AstNode::Unary(inner) => inner, AstNode::Call(inner) => inner, AstNode::Function(inner) => inner, AstNode::If(inner) => inner, AstNode::While(inner) => inner, AstNode::Begin(inner) => inner, AstNode::Assign(inner) => inner, AstNode::NewGlobal(inner) => inner, AstNode::Error(inner) => inner, AstNode::TestAssert(inner) => inner, AstNode::TestExpect(inner) => inner, } } } impl<'a> Debug for AstNode<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.inner_debug().fmt(f) } }
这种方式把变体匹配逻辑集中到一处,后续新增变体时只需修改inner_debug方法,Debug实现无需改动。
方案3:用宏批量生成代码
如果变体数量极多,手动编写匹配分支太繁琐,可以用Rust宏自动生成重复逻辑:
macro_rules! match_ast_node_inner { ($self:expr, $formatter:expr) => { match $self { AstNode::Literal(inner) => inner.fmt($formatter), AstNode::Variable(inner) => inner.fmt($formatter), AstNode::Binary(inner) => inner.fmt($formatter), AstNode::Unary(inner) => inner.fmt($formatter), AstNode::Call(inner) => inner.fmt($formatter), AstNode::Function(inner) => inner.fmt($formatter), AstNode::If(inner) => inner.fmt($formatter), AstNode::While(inner) => inner.fmt($formatter), AstNode::Begin(inner) => inner.fmt($formatter), AstNode::Assign(inner) => inner.fmt($formatter), AstNode::NewGlobal(inner) => inner.fmt($formatter), AstNode::Error(inner) => inner.fmt($formatter), AstNode::TestAssert(inner) => inner.fmt($formatter), AstNode::TestExpect(inner) => inner.fmt($formatter), } }; } impl<'a> Debug for AstNode<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match_ast_node_inner!(self, f) } }
宏可以帮你批量生成重复的匹配代码,适合变体数量多且后续可能频繁新增的场景。
内容的提问来源于stack exchange,提问作者jzimmerman
相关产品推荐
相关产品推荐

