How do I pull a reference out of an Option
and pass it back with the specific lifespan of the caller?
Specifically, I want to borrow a reference to a Box<Foo>
from a Bar
that has an Option<Box<Foo>>
in it. I thought I would be able to do:
impl Bar { fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> { match self.data { Some(e) => Ok(&e), None => Err(BarErr::Nope), } } }
...but that results in:
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`
Hm, ok. Maybe not. It looks vaguely like what I want to do is related to Option::as_ref
, like maybe I could do:
impl Bar { fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> { match self.data { Some(e) => Ok(self.data.as_ref()), None => Err(BarErr::Nope), } } }
...but, that doesn't work either.
Full code I'm having trouble with:
#[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); } }
I'm reasonably sure what I've trying to do is valid here.
An Example of Borrowing in Rust You can borrow the ownership of a variable by referencing the owner using the ampersand (&) symbol. Without borrowing by referencing, the program would panic. It would violate the ownership rule that a value can have one owner, and two variables cannot point to the same memory location.
What is Borrowing? When a function transfers its control over a variable/value to another function temporarily, for a while, it is called borrowing. This is achieved by passing a reference to the variable (& var_name) rather than passing the variable/value itself to the function.
A reference represents a borrow of some owned value. You can get one by using the & or &mut operators on a value, or by using a ref or ref mut pattern.
As of Rust 1.26, match ergonomics allows you to write:
impl Bar { fn borrow(&mut self) -> Result<&Box<Foo>, BarErr> { match &self.data { Some(e) => Ok(e), None => Err(BarErr::Nope), } } }
Prior to that, you can use Option::as_ref
, you just need to use it earlier:
impl Bar { fn borrow(&self) -> Result<&Box<Foo>, BarErr> { self.data.as_ref().ok_or(BarErr::Nope) } }
There's a companion method for mutable references: Option::as_mut
:
impl Bar { fn borrow_mut(&mut self) -> Result<&mut Box<Foo>, BarErr> { self.data.as_mut().ok_or(BarErr::Nope) } }
I'd encourage removing the Box
wrapper though.
Since Rust 1.40, you can use 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) } }
Before then, I'd probably use a 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) } }
With the match ergonomics version, you can do the mapping inline:
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), } } }
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With