传递Option<&mut T>时,何时需要使用mut修饰变量?
为什么循环中使用
Option<&mut Foo>时需要标记变量为mut? 先明确场景:我们需要给函数传入一个包裹在Option里的Foo可变引用,在循环中反复向Foo的Vec里推值,出现了两种需要mut的写法,而无循环的场景却不需要。下面逐个拆解:
先看无循环的bar3:无需mut的原因
struct Foo { value: Vec<i32>, } fn bar3(a: Option<&mut Foo>) { if let Some(x) = a { x.value.push(0); } }
这里a被直接移动到if let表达式中,整个过程只发生一次:我们取出Option内部的&mut Foo并使用,之后a就不再被任何代码访问。因为没有后续对a的操作,不需要修改a本身的状态,所以完全不需要mut修饰。
循环场景的bar和bar2:必须mut的核心逻辑
循环意味着我们需要重复访问同一个a变量,不能把它一次性移动走,必须通过借用的方式保留a的所有权,这就牵扯到Rust的借用规则:
bar的写法:通过模式匹配绕开变量mut
fn bar(a: Option<&mut Foo>) { // <do_stuff> while /* <condition> */ true { // <do_stuff> if let Some(&mut ref mut x) = a { x.value.push(1); } } }
这里a是不可变的,所以我们只能对它做不可变借用。&mut ref mut x的模式是在“重新借用”内部的可变引用:
- 先解构出
Option里的&mut Foo - 再通过
ref mut把它借用为一个新的可变引用,这样不会消耗a,循环下一次迭代还能继续访问a
bar2的写法:直接标记a为mut
fn bar2(mut a: Option<&mut Foo>) { // <do_stuff> while /* <condition> */ true { // <do_stuff> if let Some(ref mut x) = a { x.value.push(1); } } }
这里把a声明为mut,是因为我们要对Option本身进行多次可变借用:
- 每次循环里的
if let Some(ref mut x) = a,都是对mut a进行可变借用,取出内部&mut Foo的可变引用 - 使用完后借用会自动归还,下一次循环可以再次借用。如果
a不是mut,Rust的借用规则不允许对不可变变量进行多次可变借用。
总结
核心差异在于是否需要重复访问变量a:
- 无循环场景:一次性移动
a,无需修改a本身,所以不用mut - 循环场景:必须保留
a的所有权并重复访问,要么通过模式匹配从不可变a里重新借用可变引用,要么直接把a声明为mut以允许多次可变借用
内容的提问来源于stack exchange,提问作者Fleetscut
相关产品推荐
相关产品推荐

