为何循环中条件返回不可变引用会阻碍后续可变借用?
Rust借用检查器冲突错误成因解析
代码示例
fn foo(var: &mut String) -> &String { let mut counter = 1; let result = loop { { let var_ref = &*var; counter += 1; if counter > 10 { break var_ref; } } *var += "a"; }; result }
代码逻辑与问题描述
这段代码的逻辑是:循环内先为传入的可变引用var创建不可变引用var_ref,当counter≤10时,var_ref会被销毁,之后再对var追加字符串"a";当counter>10时,会在执行可变借用前退出循环。从逻辑上看,可变借用发生时var_ref已不存在,返回var_ref时也没有可变借用,但编译时触发了如下错误:
error[E0502]: cannot borrow `*var` as mutable because it is also borrowed as immutable --> src\main.rs:13:9 | 3 | fn foo(var: &mut String) -> &String { | - let's call the lifetime of this reference `'1` ... 7 | let var_ref = &*var; | ----- immutable borrow occurs here ... 13 | *var += "a"; | ^^^^^^^^^^^ mutable borrow occurs here 14 | }; 15 | result | ------ returning this value requires that `*var` is borrowed for `'1`
另外,移除函数最后一行的result返回语句后,错误会直接消失。
错误成因
Rust的借用检查器基于静态分析工作,不会去解析循环的运行时逻辑(比如counter何时会大于10),具体冲突原因如下:
- 返回值的生命周期绑定:函数签名中,返回的
&String会默认和输入的&mut String共享同一生命周期'1(Rust生命周期省略规则),这意味着返回的引用必须在整个'1周期内有效。 - 借用生命周期被静态延长:当你将
var_ref作为loop的返回值赋值给result,最终返回result时,借用检查器会认为所有循环迭代中创建的var_ref的生命周期都要覆盖到函数返回时刻(也就是'1的全周期)。 - 静态检查下的借用冲突:虽然运行时只有最后一次循环的
var_ref会被保留,前面的var_ref都已销毁,但借用检查器无法区分不同迭代的借用。它只会判断:既然存在某个var_ref需要延续到函数结束,那么整个循环过程中var都处于不可变借用状态,此时执行*var += "a"的可变借用必然和这个不可变借用产生冲突。
简单来说,借用检查器看不到“仅最后一次迭代的var_ref会被保留”这个运行时细节,它只会静态判定:只要有一次var_ref被绑定到函数的生命周期'1,所有对var的不可变借用都会被视为持续到函数结束,进而和后续的可变借用冲突。
内容的提问来源于stack exchange,提问作者Tomato105
相关产品推荐
相关产品推荐

