如何从 Option
中提取引用并将其与调用者的特定生命周期传回?
具体来说,我想借用一个 Box<Foo>
的引用来自Bar
有一个 Option<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);
}
}
我相当确定我尝试做的事情在这里是有效的。
最佳答案
从 Rust 1.26 开始,match ergonomics 允许您编写:
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
包装器。
从 Rust 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),
}
}
}
另见:
关于rust - 如何借用对 Option<T> 中内容的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22282117/