稳定版Rust中如何简洁匹配深度嵌套的Box?
稳定版Rust中深度嵌套Box/枚举的匹配方案
针对深度嵌套的Box包裹枚举结构,稳定版Rust中有几种简洁的实现方式可以替代冗长的match嵌套:
方案一:使用let-else线性匹配(推荐)
利用Rust 1.65+稳定版支持的let-else语法,可以写出无嵌套的线性代码,可读性极强:
fn extract_unsigned_number(node: &ConstantExpression) -> Option<&UnsignedNumber> { // 逐层匹配,不满足则直接返回None let ConstantExpression::ConstantPrimary(cp_box) = node else { return None }; let ConstantPrimary::PrimaryLiteral(pl_box) = cp_box else { return None }; let PrimaryLiteral::Number(n_box) = pl_box else { return None }; let Number::IntegralNumber(in_box) = n_box else { return None }; let IntegralNumber::DecimalNumber(dn_box) = in_box else { return None }; let DecimalNumber::UnsignedNumber(num) = dn_box else { return None }; Some(num) } // 使用示例 let unsigned_number = extract_unsigned_number(&node);
这种写法完全规避了深层嵌套,每一步都清晰展示了解包逻辑,而且代码简洁。
方案二:为枚举实现链式解包方法
为每个枚举类型添加as_xxx风格的方法,返回对应子类型的Option<&T>,之后通过链式调用快速定位到目标值:
// 为ConstantExpression添加解包方法 impl ConstantExpression { fn as_constant_primary(&self) -> Option<&ConstantPrimary> { match self { ConstantExpression::ConstantPrimary(inner) => Some(inner), _ => None, } } } // 为ConstantPrimary添加解包方法 impl ConstantPrimary { fn as_primary_literal(&self) -> Option<&PrimaryLiteral> { match self { ConstantPrimary::PrimaryLiteral(inner) => Some(inner), _ => None, } } } // 依次为其他枚举实现类似方法 impl PrimaryLiteral { fn as_number(&self) -> Option<&Number> { match self { PrimaryLiteral::Number(inner) => Some(inner), _ => None, } } } impl Number { fn as_integral_number(&self) -> Option<&IntegralNumber> { match self { Number::IntegralNumber(inner) => Some(inner), _ => None, } } } impl IntegralNumber { fn as_decimal_number(&self) -> Option<&DecimalNumber> { match self { IntegralNumber::DecimalNumber(inner) => Some(inner), _ => None, } } } impl DecimalNumber { fn as_unsigned_number(&self) -> Option<&UnsignedNumber> { match self { DecimalNumber::UnsignedNumber(inner) => Some(inner), _ => None, } } } // 使用示例 let unsigned_number = node.as_constant_primary() .and_then(|cp| cp.as_primary_literal()) .and_then(|pl| pl.as_number()) .and_then(|n| n.as_integral_number()) .and_then(|in_| in_.as_decimal_number()) .and_then(|dn| dn.as_unsigned_number());
这种方式的优势是解包方法可以在代码其他地方复用,适合需要多次访问嵌套结构的场景。
方案三:简化版if let嵌套
如果不想额外实现方法,也可以用多层if let替代冗长的单match语句,虽然有嵌套但比原代码可读性更好:
let unsigned_number = if let ConstantExpression::ConstantPrimary(cp_box) = &node { if let ConstantPrimary::PrimaryLiteral(pl_box) = cp_box { if let PrimaryLiteral::Number(n_box) = pl_box { if let Number::IntegralNumber(in_box) = n_box { if let IntegralNumber::DecimalNumber(dn_box) = in_box { dn_box.as_unsigned_number() } else { None } } else { None } } else { None } } else { None } } else { None };
不过这种写法嵌套层级较多,不如前两种方案简洁。
内容的提问来源于stack exchange,提问作者Timmmm
相关产品推荐
相关产品推荐

