[英]When is mut required when passing an Option<&mut T>
我有一个 function,我需要在其中传递一个结构,进行一些操作,然后将结果推送到结构中。 该结构可能存在也可能不存在,因此在我将可变引用传递给 function 之前,我将其包装在一个选项中。简化后它类似于以下内容。
似乎有两种不同的编写方式,我试图理解为什么变量 a 需要可变,即使我没有直接修改它
struct Foo {
value: Vec<i32>,
}
fn bar(a: Option<&mut Foo>) {
<do_stuff>
while <condition> {
<do_stuff>
if let Some(&mut ref mut x) = a {
x.value.push(value);
}
}
}
在 bar &mut 中需要传入 if let
fn bar2(mut a: Option<&mut Foo>) {
<do_stuff>
while <condition> {
<do_stuff>
if let Some(ref mut x) = a {
x.value.push(value);
}
}
}
在 bar2 中,a 需要在 function 声明中定义为可变的
fn bar3(a: Option<&mut Foo>){
if let Some(x) = a {
x.value.push(0);
}
}
我不认为它与正在修改的 a 中的值有关,因为没有循环 (bar3) 的相同过程不需要 a 可变。
据我了解,在 if let 语句上使用“ref mut”应该可以防止 Option 内的值在块内移动。 由于循环,这是必需的。 由于循环,是否也需要 a 的可变性? 我确信取消引用和重新共享会发生一些我在这里不理解的事情。
我意识到可能有更好的方法来做到这一点,但我只是在试图更好地理解借用的工作原理。
我很惊讶第一个代码示例完全有效,但我会尝试分解语法以查看其功能:
let a: Option<&mut Foo> =...; if let Some(x) = a { x.value.push(0); }
这是可行的,因为分配会将值移动并将所有权转移到左侧。 这不需要原始值是可变的。 在这种情况下,左侧将Option
解构为Some(x)
,其中x
是&mut Foo
。
let a: Option<&mut Foo> =...; if let Some(ref mut x) = a { x.value.push(0); }
如果不可变,这将无法工作,因为它试图可变地引用Option
a
内部值( x
将是&mut &mut Foo
)并且如果变量本身不可变,您将无法获得对变量字段的可变引用。
let a: Option<&mut Foo> =...; if let Some(&mut x) = a { x.value.push(0); }
这不是您的示例之一,但无论如何我都需要对其进行解释。 这是行不通的。 当解构时&mut
做什么本质上反映了它匹配的内容。 在这里,您将尝试将类型&mut Foo
与声明&mut x
相匹配; &mut
s 取消并且x
将是Foo
类型。 这当然会失败,因为除非它实现Copy
,否则您无法从引用中获取拥有的值。
let a: Option<&mut Foo> =...; if let Some(&mut ref mut x) = a { x.value.push(0); }
这很有趣,因为我不希望这些规则以这种方式相互作用,但我们就在这里。 似乎首先应用匹配&mut _
的规则,以便ref mut x
然后与Foo
值(未移动)匹配,这具有将x
声明为&mut Foo
的效果。 最终结果是a
的内部值被可变地重新借用,而a
本身是可变的。
这是安全的,因为您a
. 如果您使用&Option<&mut Foo>
尝试它,那么您会收到一条错误消息,指示您无法通过共享引用进行变异。
如果您正在寻找有经验的意见,我会简单地这样做并称之为一天:
let mut a: Option<&mut Foo> = ...;
if let Some(x) = &mut a {
x.value.push(0);
}
这与您的bar2
样本几乎相同,只是写法略有不同。 ref
/ ref mut
的使用大多已经过时了,因为引入了匹配人体工程学,这使得它们几乎没有必要(除了一些模糊的情况)。 如果我将来需要它,我会记住这种模式:)。
那么, “[使用] Option<&mut T> 时什么时候需要 mut” ? Option
的所有非消耗方法授予对其内部值的可变访问权限(需要可变地使用它或可变地重新借用它)需要&mut
访问Option
。 所以答案几乎总是如此,除非您发现情况并非如此(因为它不依赖于 function 调用)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.