I'm trying to have a struct which lazily instantiates one of it's members, and I am running into lifetime issues.
Here's the approach I have tried:
pub struct Bar;
impl Bar {
fn new() -> Bar {
Bar
}
}
pub struct Foo {
bar: Option<Bar>,
}
impl Foo {
fn bar<'a, 'b>(&'a mut self) -> Result<&'b mut Bar>
where
'a: 'b,
{
match &mut self.bar {
Some(bar) => return Ok(bar),
None => {}
}
let bar = Bar::new();
self.bar = Some(bar);
self.bar()
}
}
So here the bar function on Foo should return foo.bar if it exists, and instantiate it first if needed.
When I try to compile, I get this error:
error[E0506]: cannot assign to `self.bar` because it is borrowed
--> crates/foo/foo.rs:125:9
|
116 | fn bar<'a, 'b>(&'a mut self) -> Result<&'b mut Bar>
| -- lifetime `'b` defined here
...
120 | match &mut self.bar {
| ------------- borrow of `self.bar` occurs here
121 | Some(bar) => return Ok(bar),
| ------- returning this value requires that `self.bar` is borrowed for `'b`
...
125 | self.bar = Some(bar);
| ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.bar` occurs here
Is there any way to implement this pattern, or achieve the same result in Rust?
You're running into a limitation of the borrow checker, which requires a workaround of checking if the option is some before borrowing it. The optimizer should be able to compile this code to the same level of performance as what you have.
impl Foo {
fn bar(&mut self) -> Result<&mut Bar, ()> {
if self.bar.is_some() {
Ok(self.bar.as_mut().unwrap())
} else {
let bar = Bar::new();
self.bar = Some(bar);
self.bar()
}
}
}
playground
Relevant issue: https://github.com/rust-lang/rust/issues/54663
More information: https://docs.rs/polonius-the-crab/0.3.1/polonius_the_crab/
Related
Rust-lang Playground link
struct Foo {
val: i32
}
impl Foo {
pub fn maybe_get(&mut self) -> Option<&mut i32> {
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
{ // Add closure to ensure things have a chance to get dropped
if let Some(val) = self.maybe_get() {
// Explicit return to avoid potential scope sharing with an else block or a match arms.
return val;
}
}
// One would think any mutable references would not longer be at play at this point
&mut self.val
}
}
I have some code that's similar but more complicated than what is provided above that I've been fighting with for quite a while. The borrow checker is unhappy with the implementation of definitely_get and has the following error
error[E0499]: cannot borrow `self.val` as mutable more than once at a time
--> src/main.rs:19:9
|
10 | pub fn definitely_get(&mut self) -> &mut i32 {
| - let's call the lifetime of this reference `'1`
11 | {
12 | if let Some(val) = self.maybe_get() {
| ---------------- first mutable borrow occurs here
13 | return val;
| --- returning this value requires that `*self` is borrowed for `'1`
...
19 | &mut self.val
| ^^^^^^^^^^^^^ second mutable borrow occurs here
It seems unreasonable for there to be no way to implement fallback logic with a mutable reference in Rust so I can't imagine there isn't a way.
I've managed to fix this with an unfortunately expensive alternative implementation due to how maybe_get is implemented in my non-trivial example.
impl Foo {
pub fn has_maybe_val(&self) -> bool {
// Non-trivial lookup...
true
}
pub fn maybe_get(&mut self) -> Option<&mut i32> {
// Same non-trivial lookup...
Some(&mut self.val)
}
pub fn definitely_get(&mut self) -> &mut i32 {
if self.has_maybe_val() {
self.maybe_get().unwrap() // Ouch!
} else {
&mut self.val
}
}
}
I'm playing around with building a very simple stack based evaluator in Rust. I want the user to be able to define functions later, so I'm storing all operators in a HashMap with closures as values.
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator<'a> {
stack: Vec<Value>,
ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)>,
}
impl<'a> Evaluator<'a> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'a dyn FnMut(&'a mut Vec<Value>)> = HashMap::new();
ops.insert("+".to_string(), &|stack: &'a mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
});
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&'a mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
I'm currently getting two errors:
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:34:17
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
34 | self.stack.push(n);
| ^^^^^^^^^^ second mutable borrow occurs here
...
38 | f(&mut self.stack);
| ------------------
| | |
| | first mutable borrow occurs here
| argument requires that `self.stack` is borrowed for `'a`
error[E0596]: cannot borrow `**f` as mutable, as it is behind a `&` reference
--> src/sample.rs:38:21
|
38 | f(&mut self.stack);
| ^ cannot borrow as mutable
error[E0499]: cannot borrow `self.stack` as mutable more than once at a time
--> src/sample.rs:38:23
|
10 | impl<'a> Evaluator<'a> {
| -- lifetime `'a` defined here
...
38 | f(&mut self.stack);
| --^^^^^^^^^^^^^^^-
| | |
| | `self.stack` was mutably borrowed here in the previous iteration of the loop
| argument requires that `self.stack` is borrowed for `'a`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0499, E0596.
For more information about an error, try `rustc --explain E0499`.
My concern is the first one. I'm not sure what I'm doing wrong as I'm not borrowing them at the same time. Can I tell Rust the previous borrow (self.stack.pop()) is done? Any help appreciated.
I think I solved my problem. The thing I kept coming back to is, "What owns the closures?" In this case I'm using references, but nothing is taking ownership of the data. When I refactored (below) with Box to take ownership, it worked.
I'm curious if there is a way to do this with with just references and/or if my explanation is wrong?
Working code:
use std::collections::HashMap;
pub type Value = i32;
pub struct Evaluator {
stack: Vec<Value>,
ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>>,
}
impl Evaluator {
pub fn new() -> Evaluator {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, Box<dyn FnMut(&mut Vec<Value>)>> = HashMap::new();
ops.insert("+".to_string(), Box::new(|stack: &mut Vec<Value>| {
if let (Some(x), Some(y)) = (stack.pop(), stack.pop()) {
stack.push(y + x);
}
}));
Evaluator { stack, ops }
}
pub fn stack(&self) -> &[Value] {
&self.stack
}
pub fn eval(&mut self, input: &str) {
let symbols = input
.split_ascii_whitespace()
.collect::<Vec<_>>();
for sym in symbols {
if let Ok(n) = sym.parse::<i32>() {
self.stack.push(n);
} else {
let s = sym.to_ascii_lowercase();
if let Some(f) = self.ops.get_mut(&s) {
f(&mut self.stack);
} else {
println!("error");
}
}
}
}
}
fn main() {
let mut e = Evaluator::new();
e.eval("1 2 +")
}
You have borrows with conflicting lifetimes:
You are defining a lifetime 'a for the struct in line 5: pub struct Evaluator<'a> {
In line 7, you are stating that ops is a HashMap that holds functions that receive mutable borrows for the whole duration of 'a
Then, in line 28, you are defining an eval method that holds a mutable reference to self for the whole duration of the struct ('a)
The conflict can be solved if you use two different lifetimes, since the time that an operation borrows self should be inherently shorter than the lifetime for the whole evaluation, since in eval you are running a loop and multiple invocations to the operations.
This should fix the issues mentioned above:
pub struct Evaluator<'a, 'b> {
stack: Vec<Value>,
ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)>,
}
impl<'a, 'b> Evaluator<'a, 'b> {
pub fn new() -> Evaluator<'a> {
let stack: Vec<Value> = vec![];
let mut ops: HashMap<String, &'b dyn FnMut(&'b mut Vec<Value>)> = HashMap::new();
The following code doesn't compile:
struct Things {
things: Vec<usize>
}
struct ThingsIterMut<'a> {
contents: &'a mut Vec<usize>,
indices: std::slice::Iter<'a, usize>
}
impl<'a> Iterator for ThingsIterMut<'a> {
type Item = &'a mut usize;
fn next(&mut self) -> Option<Self::Item> {
match self.indices.next() {
None => None,
Some(i) => self.contents.get_mut(*i)
}
}
}
impl Things {
pub fn iter_mut<'a>(&'a mut self) -> ThingsIterMut<'a> {
ThingsIterMut {
contents: &mut self.things,
indices: self.things.iter()
}
}
}
fn main() {
println!("Hello, world!");
}
It complains:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:16:24
|
16 | Some(i) => self.contents.get_mut(*i)
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 13:5...
--> src/main.rs:13:5
|
13 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:16:24
|
16 | Some(i) => self.contents.get_mut(*i)
| ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 10:6...
--> src/main.rs:10:6
|
10 | impl<'a> Iterator for ThingsIterMut<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:13:46
|
13 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
14 | | match self.indices.next() {
15 | | None => None,
16 | | Some(i) => self.contents.get_mut(*i)
17 | | }
18 | | }
| |_____^
= note: expected `std::iter::Iterator`
found `std::iter::Iterator`
Changing next to next(&'a mut self) dose not work (signature mismatch), neither does change self.contents.get_mut() to self.contents.get_mut::<'a>().
What's the correct way to address this issue?
I see two problems. The first is that your iter_mut function tries to return both a mutable and an immutable reference to self.things.
It is easier to see why the borrow checker doesn't allow this by simplifying it:
fn main() {
let mut things = vec![1, 2, 3];
let contents = &mut things;
let indices = things.iter(); // borrows self_things immutably
let things_iter_mut = (contents, indices);
}
The second problem that you are trying to return a longer reference than you pass into the next function.
struct Things<'things> {
contents: &'things mut Vec<usize>,
}
impl<'things> Things<'things> {
// This won't compile! The 'borrow lifetime is implied.
// But here you can see that the borrow might be shorter than
// what we are returning.
fn next(&'borrow mut self) -> &'things mut Vec<usize> {
self.contents
}
// This will compile. Because the returned reference lives
// just as long as the argument.
fn next(&'things mut self) -> &'things mut Vec<usize> {
self.contents
}
}
I want to write the equivalent of this C++ in Rust:
struct Bar { int x; };
struct Foo { Bar* bar; };
void main() {
Bar bar { 42 };
Foo foo { &bar };
Bar bar2 { 50 };
foo.bar = &bar2;
printf("%d\n", foo.bar->x);
}
The C++ sets up a structure, then swaps out a Bar object with another Bar object. This is the code I've tried:
struct Bar(isize);
impl Bar {
fn new(i: isize) -> Bar { Bar(i) }
}
struct Foo<'a> {
bar: Option<&'a Bar>,
}
impl<'a> Foo<'a> {
fn new(bar: &Bar) -> Foo {
Foo { bar: Some(&bar) }
}
}
fn main() {
// Set up first state
let bar = Bar::new(42);
let mut foo = Foo::new(&bar);
// Replace bar object
let bar2 = Bar::new(50);
foo.bar = Some(&bar2);
if let Some(e) = foo.bar {
println!("{}", e.0);
}
}
This code complains:
error[E0597]: `bar2` does not live long enough
--> src/main.rs:22:21
|
22 | foo.bar = Some(&bar2);
| ^^^^ borrowed value does not live long enough
...
27 | }
| - `bar2` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Is it possible in Rust to have a structure that has a reference to a sub-structure whose lifetime can be shorter (i.e. you can replace the sub-structure instance with another instance)?
I looked at some other answers, and tried to split up the structure:
struct Bar(isize);
impl Bar {
fn new(i: isize) -> Bar {
Bar(i)
}
}
struct FooCore {
a: isize,
}
struct Foo<'c, 'a> {
core: &'c FooCore,
bar: &'a Bar,
}
impl<'c, 'a> Foo<'c, 'a> {
fn new(core: &'c FooCore, bar: &'a Bar) -> Foo<'c, 'a> {
Foo {
core: &core,
bar: &bar,
}
}
}
fn main() {
// Set up first state
let core = FooCore { a: 10 };
let bar = Bar::new(42);
let _foo = Foo::new(&core, &bar);
// Replace bar object
let bar2 = Bar::new(50);
let foo = Foo::new(&core, &bar2);
println!("{} {}", foo.core.a, foo.bar.0);
}
This compiles and works, however, as soon as I make the core and bar fields mutable, it falls apart. Below is code that uses mut:
#![allow(unused_mut)]
struct Bar(isize);
impl Bar {
fn new(i: isize) -> Bar {
Bar(i)
}
}
struct FooCore {
a: isize,
}
struct Foo<'c, 'a> {
core: &'c mut FooCore,
bar: &'a mut Bar,
}
impl<'c, 'a> Foo<'c, 'a> {
fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
Foo {
core: &mut core,
bar: &mut bar,
}
}
}
fn main() {
// Set up first state
let mut core = FooCore { a: 10 };
let mut bar = Bar::new(42);
let mut _foo = Foo::new(&mut core, &mut bar);
// Replace bar object
let mut bar2 = Bar::new(50);
let mut foo = Foo::new(&mut core, &mut bar2);
println!("{} {}", foo.core.a, foo.bar.0);
}
This results in the errors:
error[E0597]: `core` does not live long enough
--> src/main.rs:21:24
|
21 | core: &mut core,
| ^^^^ borrowed value does not live long enough
...
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'c as defined on the impl at 18:1...
--> src/main.rs:18:1
|
18 | impl<'c, 'a> Foo<'c, 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0597]: `bar` does not live long enough
--> src/main.rs:22:23
|
22 | bar: &mut bar,
| ^^^ borrowed value does not live long enough
23 | }
24 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 18:1...
--> src/main.rs:18:1
|
18 | impl<'c, 'a> Foo<'c, 'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error[E0499]: cannot borrow `core` as mutable more than once at a time
--> src/main.rs:35:33
|
31 | let mut _foo = Foo::new(&mut core, &mut bar);
| ---- first mutable borrow occurs here
...
35 | let mut foo = Foo::new(&mut core, &mut bar2);
| ^^^^ second mutable borrow occurs here
...
38 | }
| - first borrow ends here
How do I structure my data to achieve what I want?
The obvious problem is that you are taking a reference to a reference unnecesarily:
In this code, core and bar are already references, so no need to get its address:
impl<'c, 'a> Foo<'c, 'a> {
fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
Foo {
core: &mut core,
bar: &mut bar,
}
}
}
Write instead:
impl<'c, 'a> Foo<'c, 'a> {
fn new(core: &'c mut FooCore, bar: &'a mut Bar) -> Foo<'c, 'a> {
Foo {
core: core,
bar: bar,
}
}
}
About the subobject living longer than the main object, the general answer is "no, you can't", because the reference could be left dangling and Rust will not allow it. There are workarounds, as the linked answer in the comments above shows.
As an extra workaround to mimic your C code, you could write:
fn main() {
// Set up first state
let mut core = FooCore { a: 10 };
let mut bar = Bar::new(42);
let mut bar2; //lifetime of bar2 is greater than foo!
let mut foo = Foo::new(&mut core, &mut bar);
bar2 = Bar::new(50); //delayed initialization
// Replace bar object
foo.bar = &mut bar2;
println!("{} {}", foo.core.a, foo.bar.0);
}
When constructing a FooBuilder, I want to provide a &mut Bar. When I build Foo I want to provide a &Bar and Foo should be able to invoke &self methods from Bar. In other words, the mutable borrow should only during exist during the life of FooBuilder.
struct FooBuilder<'a> {
bar: &'a mut Bar,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Bar) -> Self {
FooBuilder { bar: bar }
}
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
}
struct Foo<'a> {
bar: &'a Bar,
}
struct Bar;
impl Bar {
fn bar(&self) {}
}
fn main() {
let mut bar = Bar;
let foo = FooBuilder::new(&mut bar).build();
bar.bar();
}
This code has the error:
error: borrowed value does not live long enough
--> <anon>:24:15
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
|
note: reference must be valid for the block suffix following statement 1 at 24:48...
--> <anon>:24:49
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^
note: ...but borrowed value is only valid for the statement at 24:4
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: consider using a `let` binding to increase its lifetime
--> <anon>:24:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0502]: cannot borrow `bar` as immutable because it is also borrowed as mutable
--> <anon>:25:5
|
24 | let foo = FooBuilder::new(&mut bar).build();
| --- mutable borrow occurs here
25 | bar.bar();
| ^^^ immutable borrow occurs here
26 | }
| - mutable borrow ends here
error: aborting due to 2 previous errors
The first step is to fix build.
In order to transform a &mut T into a &T you need to consume &mut T (otherwise you would have aliasing and mutability). This means:
consuming the builder, not taking a reference to it
passing the mutable reference, not taking a reference to it
In short, you go from:
fn build(&'a self) -> Foo<'a> {
Foo { bar: &self.bar }
}
to:
fn build(self) -> Foo<'a> {
Foo { bar: self.bar }
}
This leaves you with a single error:
error: cannot borrow `bar` as immutable because it is also borrowed as mutable [--explain E0502]
--> <anon>:25:5
24 |> let foo = FooBuilder::new(&mut bar).build();
|> --- mutable borrow occurs here
25 |> bar.bar();
|> ^^^ immutable borrow occurs here
26 |> //foo.bar.bar();
27 |> }
|> - mutable borrow ends here
As far as the compiler can see from the method signatures, bar is borrowed mutably and therefore cannot be used directly. The borrow extends until foo is dropped.
The fix is very simple: instead of using bar directly, use bar from its reference in foo. Or to make it clear that scope matters:
fn main() {
let mut bar = Bar;
{
let foo = FooBuilder::new(&mut bar).build();
// `bar` currently borrow (mutably) by `foo`, cannot use it directly
foo.bar.bar();
}
// `bar` no longer borrowed, use at your heart's content
bar.bar();
}
You can do something similar if you don't mind wrapping bar in an Rc. The trick is that if there's only one Rc reference, you can get an &mut reference to the contents. This is sort of backwards; instead of downgrading &mut to & at compile time, it's making use of runtime information (reference counts) to "upgrade" from an immutable reference to mutable.
use std::rc::Rc;
struct FooBuilder<'a> {
bar: &'a mut Rc<Bar>,
}
impl<'a> FooBuilder<'a> {
fn new(bar: &'a mut Rc<Bar>) -> Self {
FooBuilder { bar: bar }
}
fn f(mut self) -> Self {
Rc::get_mut(self.bar).unwrap().mut_method();
self
}
fn build(&'a self) -> Foo {
Foo { bar: self.bar.clone() }
}
}
struct Foo {
bar: Rc<Bar>,
}
struct Bar;
impl Bar {
fn bar(&self) {}
fn mut_method(&mut self) {}
}
fn main() {
let mut bar = Rc::new(Bar);
let foo = FooBuilder::new(&mut bar).f().build();
bar.bar();
}
Play link
Once the Foo has been constructed with an Rc clone, there is more than one reference and a later attempt to get a mut reference would panic (or at least return None from Rc::get_mut()).
This means that you can only do this once; if you want a second FooBuilder to create a second Foo from the same bar it won't work, as you're not allowed any other references if you have an &mut T.
This is a little clumsy, though, and there are likely to be better ways of solving the actual problem, depending on the circumstances.