rust 从选项中提取可变引用

rbpvctlc  于 2022-12-19  发布在  其他
关注(0)|答案(2)|浏览(101)

有没有从Option<&mut Foo>中提取可变引用的选项?我找到的是as_ref(),它提取的是不可变引用。

lf5gs5x2

lf5gs5x21#

是否有任何选项可以提取Option<&mut Foo>外部的可变引用。
是的,但是要防止消耗Option需要付出一些努力,因为&mut T不是Copy
让我们假设您有一个Option<&mut Foo>,它是Some。(这同样适用于非-Some选项,只是用适当的匹配替换unwrap()。)例如:

let mut foo = Foo;
let mut opt = Some(&mut foo);

opt.unwrap()会给予你&mut Foo,但是它会把它移出Option,因为&mut Foo不是Copy

let mut_ref = opt.unwrap();
drop(mut_ref);          // done with mut_ref
println!("{:?}", opt);  // XXX doesn't compile, opt is consumed

这将使Option无法使用,即使mut_ref超出作用域,我们不希望这样,我们希望 * 借用 * 选项的内部,并在删除借用后保留Option的使用,为此我们可以使用Option::as_mut

let mut_ref_ref = opt.as_mut().unwrap();
drop(mut_ref_ref);
println!("{:?}", opt);  // compiles

这里有两点需要注意:首先,您需要使用as_mut(),而不是您尝试使用的as_ref(),因为as_ref()会在共享引用后面给予您一个可变引用,这会使它变得无用;其次,展开as_mut()返回一个&mut &mut Foo,而不是我们想要的&mut Foo。自动解引用允许调用接受&mut Foo的函数:

fn wants_ref(_r: &mut Foo) {}
let mut_ref_ref = opt.as_mut().unwrap();  // got &mut &mut Foo
wants_ref(mut_ref_ref);  // but we can send it to fn expecting &mut Foo

如果出于某种原因需要一个实际的&mut Foo,人们会认为可以通过解引用&mut &mut Foo来获得它。

// XXX doesn't compile
let mut_ref = *opt.as_mut().unwrap();

因为*试图解引用&mut &mut Foo并提取底层的&mut Foo,所以不能编译,但是&mut Foo不是Copy,所以这是试图“移出一个可变引用”,rustc会告诉你不能这样做。但是,在这种情况下,它可以,你需要执行一个显式的reborrow,即将EXPR转到&mut *EXPR,其中EXPR计算为可变引用。&mut *EXPR将创建一个对同一数据的 new 可变引用。它不算作别名,因为旧的可变引用将(静态不可用),直到删除新的引用。这基本上与允许 projection 在可变引用上工作的机制相同(即let x_ref = &mut point.x,其中point&mut Point)-但应用于对象本身。
使用显式重借时,它如下所示:

// `&mut *` is reborrow, and `*` dereferences `&mut &mut Foo`
let mut_ref = &mut **opt.as_mut().unwrap();
wants_ref(mut_ref);
println!("{:?}", opt);  // opt is still usable

Playground

yruzcnhs

yruzcnhs2#

正确的方法是使用as_mut()方法。
需要注意的一点是,您需要满足&mut self参数类型,关键的一点是,如果您拥有Option<&mut Foo>值,则可以安全地将其转换为mut版本(因为您是它的唯一拥有者)。
因此,总体而言,您可以执行以下操作:

let maybe_foo: Option<&mut Foo> = Some(&mut foo);

let mut maybe_foo = maybe_foo;
if let Some(mutable_reference_to_foo) = maybe_foo.as_mut() {
    ...
}

Playground

相关问题