Rust中无类型注解闭包引发多次可变借用错误的原因探究
Rust闭包可变借用错误的原因解析
问题现象
在处理Rust闭包时会碰到这样的情况:使用无类型注解的闭包时,调用不同闭包能正常运行,但重复调用同一个闭包会触发error[E0499]多次可变借用错误;给闭包参数加上显式类型注解后,问题就解决了。
正常运行的代码
fn main() { let mut st = "add: ".to_string(); let add_one = |str| add(str,1); let add_two = |str| add(str,2); add_one(&mut st); add_two(&mut st); println!("add: {:?} ",st); } fn add(str: &mut String,num:i32) { str.push_str(&num.to_string()) }
触发错误的代码
fn main() { let mut st = "add: ".to_string(); let add_one = |str| add(str,1); let add_two = |str| add(str,2); add_one(&mut st); //add_two(&mut st); for clearly I comment this line add_one(&mut st); println!("add: {:?} ",st); } fn add(str: &mut String,num:i32) { str.push_str(&num.to_string()) }
编译器错误信息
error[E0499]: cannot borrow `st` as mutable more than once at a time --> src\main.rs:13:13 | 11 | add_one(&mut st); | ------- first mutable borrow occurs here 12 | //add_two(&mut st); for clearly I comment this line 13 | add_one(&mut st); | ------- ^^^^^^^ second mutable borrow occurs here | | | first borrow later used by call
修复后的代码
fn main() { let mut st = "add: ".to_string(); let add_one = |str:&mut String| add(str,1);//explicit type let add_two = |str| add(str,2); add_one(&mut st); add_two(&mut st); add_one(&mut st); println!("add: {:?} ",st); //add: "add: 121" } fn add(str: &mut String,num:i32) { str.push_str(&num.to_string()) }
原因分析
核心差异在于Rust编译器对闭包参数的类型推断逻辑:
- 无类型注解的闭包:编译器会根据第一次调用的上下文,把闭包参数的类型和生命周期固定下来。第一次调用
add_one(&mut st)时,参数str被推断为&'a mut String('a是变量st的生命周期),这个生命周期会被绑定到闭包的类型中。当第二次调用add_one(&mut st)时,编译器认为第一次的借用生命周期还没结束(因为闭包类型里的'a还在生效),所以不允许再次可变借用,触发错误。 - 带显式类型注解的闭包:当你指定
str:&mut String时,编译器会自动为这个参数添加泛型生命周期(等价于<'a> &'a mut String)。这意味着每次调用闭包时,都会绑定一个临时的新生命周期,两次调用的借用生命周期互不重叠,自然就不会触发借用冲突。
另外,调用不同闭包时没问题的原因是:两个闭包被推断为完全不同的类型,各自的借用生命周期只在自身调用期间有效,第一个闭包调用结束后借用就释放了,第二个闭包可以重新借用st。
内容的提问来源于stack exchange,提问作者gray
相关产品推荐
相关产品推荐

