Rust构建基于栈的求值器时出现多重可变借用错误如何解决
错误根源
- E0499报错的核心原因:代码中为闭包参数
&'a mut Vec<Value>绑定了与Evaluator<'a>完全一致的生命周期'a,该约束要求传入闭包的栈可变借用必须在整个Evaluator实例的生命周期内持续有效,因此第一次调用闭包后借用不会释放,后续所有操作栈的逻辑都会触发重复借用错误。生命周期约束是你手动标注的,编译器会严格遵循该约束判断借用有效性,不会认为调用完闭包后借用就结束。 - E0596报错的核心原因:HashMap中存储的是
&'a dyn FnMut类型的不可变引用,而FnMut trait的调用需要获取自身的可变引用,不可变引用无法调用可变的FnMut对象,因此报错。
修复方案
核心优化点为移除不必要的生命周期绑定,使用Box持有闭包所有权避免引用带来的约束问题:
- 移除Evaluator结构体的生命周期标注,HashMap中存储
Box<dyn FnMut(&mut Vec<Value>)>类型的闭包,闭包参数不需要绑定全局生命周期,仅在调用时临时生效即可。 - 插入运算符闭包时使用
Box::new包裹闭包,直接将闭包所有权转移到HashMap中,不需要用引用存储。 - 调整eval方法的签名,移除self的生命周期绑定,查询运算符时使用
get_mut获取闭包的可变引用才能完成调用。
修复后的完整可运行代码如下:
use std::collections::HashMap; pub type Value = i32; pub struct Evaluator { stack: Vec<Value>, ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>>, } impl Evaluator { pub fn new() -> Evaluator { let stack = Vec::new(); let mut ops = HashMap::new(); ops.insert("+".to_string(), Box::new(|stack: &mut Vec<Value>| { if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) { stack.push(y + x); } })); Evaluator { stack, ops } } pub fn stack(&self) -> &[Value] { &self.stack } pub fn eval(&mut self, input: &str) { let symbols = input.split_ascii_whitespace().collect::<Vec<_>>(); for sym in symbols { if let Ok(n) = sym.parse::<i32>() { self.stack.push(n); } else { let s = sym.to_ascii_lowercase(); if let Some(f) = self.ops.get_mut(&s) { f(&mut self.stack); } else { println!("error"); } } } } } fn main() { let mut e = Evaluator::new(); e.eval("1 2 +"); assert_eq!(e.stack(), &[3]); }
修复后代码可正常编译运行,执行示例输入1 2 +后栈中会得到正确的计算结果3。后续扩展自定义函数时,直接往ops HashMap中插入Box包裹的自定义闭包即可。
内容的提问来源于stack exchange,提问作者marcantonio
相关产品推荐
相关产品推荐

