我如何借用一个引用到一个选项 < T > 中的内容?

如何从 Option中提取一个引用并将其传递给调用者的特定生命周期?

具体来说,我想从一个包含 Option<Box<Foo>>Bar中借用一个对 Box<Foo>的引用。我以为我能做到:

impl Bar {
fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
match self.data {
Some(e) => Ok(&e),
None => Err(BarErr::Nope),
}
}
}

但结果是:

error: `e` does not live long enough
--> src/main.rs:17:28
|
17 |             Some(e) => Ok(&e),
|                            ^ does not live long enough
18 |             None => Err(BarErr::Nope),
19 |         }
|         - borrowed value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the body at 15:54...
--> src/main.rs:15:55
|
15 |       fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
|  _______________________________________________________^ starting here...
16 | |         match self.data {
17 | |             Some(e) => Ok(&e),
18 | |             None => Err(BarErr::Nope),
19 | |         }
20 | |     }
| |_____^ ...ending here


error[E0507]: cannot move out of borrowed content
--> src/main.rs:16:15
|
16 |         match self.data {
|               ^^^^ cannot move out of borrowed content
17 |             Some(e) => Ok(&e),
|                  - hint: to prevent move, use `ref e` or `ref mut e`

好吧。也许不是。它看起来有点像我想做的事情和 Option::as_ref有关,就像我可以做的那样:

impl Bar {
fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
match self.data {
Some(e) => Ok(self.data.as_ref()),
None => Err(BarErr::Nope),
}
}
}

但是,那也不管用。

完整的代码,我有麻烦:

#[derive(Debug)]
struct Foo;


#[derive(Debug)]
struct Bar {
data: Option<Box<Foo>>,
}


#[derive(Debug)]
enum BarErr {
Nope,
}


impl Bar {
fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
match self.data {
Some(e) => Ok(&e),
None => Err(BarErr::Nope),
}
}
}


#[test]
fn test_create_indirect() {
let mut x = Bar { data: Some(Box::new(Foo)) };
let mut x2 = Bar { data: None };
{
let y = x.borrow();
println!("{:?}", y);
}
{
let z = x2.borrow();
println!("{:?}", z);
}
}

我有理由相信我所做的在这里是有效的。

34525 次浏览

首先,你不需要 &mut self

在进行匹配时,应该将 e作为引用进行匹配。您正在尝试返回 e的引用,但它的生存期仅针对该匹配语句。

enum BarErr {
Nope
}


struct Foo;


struct Bar {
data: Option<Box<Foo>>
}


impl Bar {
fn borrow(&self) -> Result<&Foo, BarErr> {
match self.data {
Some(ref x) => Ok(x),
None => Err(BarErr::Nope)
}
}
}

从 Rust 1.26开始,符合人体工程学允许你写:

impl Bar {
fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> {
match &self.data {
Some(e) => Ok(e),
None => Err(BarErr::Nope),
}
}
}

在此之前,您可以使用 Option::as_ref,您只需要更早地使用它:

impl Bar {
fn borrow(&self) -> Result<&Box<Foo>, BarErr> {
self.data.as_ref().ok_or(BarErr::Nope)
}
}

对于可变引用,还有一个相关的方法: Option::as_mut:

impl Bar {
fn borrow_mut(&mut self) -> Result<&mut Box<Foo>, BarErr> {
self.data.as_mut().ok_or(BarErr::Nope)
}
}

不过我建议移除 Box包装。

由于锈蚀1.40,你可以使用 Option::as_deref/Option::as_deref_mut:

impl Bar {
fn borrow(&self) -> Result<&Foo, BarErr> {
self.data.as_deref().ok_or(BarErr::Nope)
}


fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
self.data.as_deref_mut().ok_or(BarErr::Nope)
}
}

在那之前,我可能会用 map

impl Bar {
fn borrow(&self) -> Result<&Foo, BarErr> {
self.data.as_ref().map(|x| &**x).ok_or(BarErr::Nope)
}


fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
self.data.as_mut().map(|x| &mut **x).ok_or(BarErr::Nope)
}
}

使用匹配的人机工程学版本,您可以内联地进行映射:

impl Bar {
fn borrow(&mut self) -> Result<&Foo, BarErr> {
match &self.data {
Some(e) => Ok(&**e),
None => Err(BarErr::Nope),
}
}


fn borrow_mut(&mut self) -> Result<&mut Foo, BarErr> {
match &mut self.data {
Some(e) => Ok(&mut **e),
None => Err(BarErr::Nope),
}
}
}

参见: