Rust中覆写enum变量并获取associated data引用的更优写法及冗余分支release build编译疑问
Rust中覆写enum变量并获取associated data引用的更优写法及冗余分支release build编译疑问
首先针对你的第一个问题——有没有更简洁的方式避免那个“不可能触发”的else panic分支,目前Rust标准库还没有完全等价于C++std::variant::emplace的构造,这主要是受限于Rust的所有权模型:你没法在把新变体赋值给变量的同时,直接拿到关联数据的引用(赋值是移动操作,新值完全落地前无法安全引用)。不过我们可以用一些小技巧减少样板代码:
1. 封装成工具函数
把覆写enum和获取引用的逻辑封装到一个小函数里,把unreachable!()的样板藏起来,调用处就会干净很多:
fn choose_u64() -> u64 { 1234 } #[derive(Debug)] enum E { V1(), V2(u64) } // 封装emplace V2的逻辑 fn emplace_v2(e: &mut E, value: u64) -> &u64 { *e = E::V2(value); match e { E::V2(n) => n, _ => unreachable!("We just set e to V2, this can't happen!"), } } fn main() { let mut e = E::V1(); // 调用工具函数,直接拿到引用,不用写分支 let n = emplace_v2(&mut e, choose_u64()); println!("I emplaced: {n}"); }
2. 使用let-else结合代码块(稍简洁但仍需unreachable)
如果不想额外写函数,可以把赋值和引用获取放到一个代码块里,让逻辑更紧凑:
fn choose_u64() -> u64 { 1234 } #[derive(Debug)] enum E { V1(), V2(u64) } fn main() { let mut e = E::V1(); let n = { e = E::V2(choose_u64()); let E::V2(val) = &e else { unreachable!() }; val }; println!("I emplaced: {n}"); }
这里的unreachable!()还是没法完全去掉,但至少把它和核心逻辑绑定在一起,看起来不那么突兀。
然后是你的第二个问题:release构建中,那个不可能分支会不会生成实际代码?
放心,在release模式下,Rust的优化器会完全消除这些不可能分支的代码。编译器可以静态分析出这个分支永远不会被执行到(因为你刚刚把变量设置为V2变体),所以panic!或者unreachable!()的内容不会生成任何机器码,它纯粹是满足编译器穷尽性检查的语法要求而已。你可以通过查看编译后的汇编代码验证这一点——release构建里不会有任何和这个分支相关的指令。
内容来源于stack exchange
相关产品推荐
相关产品推荐

