如何在Rust闭包中实现可变重借用?
解决方案:让闭包通过接收可变引用实现重借用
先上能正常运行的修改后代码:
struct A { x: i32, } impl A { fn do_A(&mut self) { self.x = 1; } fn do_B(&mut self) { self.x = 2; } // 调整函数参数,让闭包接收当前实例的可变引用 fn do_A_and_something(&mut self, mut something: impl FnMut(&mut Self)) { self.do_A(); // 传入self的可变重借用,和do_A_and_B里的逻辑一致 something(&mut *self); } fn do_A_and_B(&mut self) { self.do_A(); self.do_B(); } } fn main() { let mut a = A { x: 0 }; // 闭包接收可变引用,不再直接捕获外部的a a.do_A_and_something(|this| this.do_B()); }
为啥原来的写法不行?
原来的闭包|| a.do_B()直接捕获了a的可变引用,而调用a.do_A_and_something本身又需要对a做一次可变借用——这就等于同时存在两个独立的可变引用,直接触发Rust的借用规则报错。
修改思路的核心
do_A_and_B能运行,是因为调用self.do_B()时,Rust会自动对self做可变重借用:把当前函数持有的&mut self再临时借出一个新的可变引用,作用域只在do_B()调用期间,和原引用是嵌套关系,不违反规则。
要让闭包也用上这个逻辑,就得把self的可变引用传递给闭包,而不是让闭包自己去捕获外部的a。修改后的do_A_and_something让闭包接收&mut Self,然后在函数内部传入&mut *self(这就是手动触发可变重借用),这样闭包里的引用和函数持有的引用是嵌套关系,完全符合规则。
另一种可选写法(不推荐)
你也可以通过提前把a的可变引用单独拿出来,让闭包捕获这个引用,Rust的借用分析也能通过:
fn main() { let mut a = A { x: 0 }; let a_ref = &mut a; a_ref.do_A_and_something(|| a_ref.do_B()); }
但这种写法依赖编译器对作用域的精确分析,可读性和扩展性都不如第一种传递引用的方式。
内容的提问来源于stack exchange,提问作者Rufus
相关产品推荐
相关产品推荐

