Small example to illustrate the problem. The following compiles:
fn main() {
let value: u32 = 15;
let mut ref_to_value: &u32 = &0;
fill_object(&mut ref_to_value, &value);
println!("referring to value {}", ref_to_value);
}
fn fill_object<'a>(m: &mut &'a u32, v: &'a u32) {
*m = v;
}
Now, the following gives a compile time error about mutable borrow followed by immutable borrow:
fn fill_object<'a>(m: &'a mut &'a u32, v: &'a u32) {
*m = v;
}
fill_object(&mut ref_to_value, &value);
| ----------------- mutable borrow occurs here
5 | println!("referring to value {}", ref_to_value);
| ^^^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
Why? I'm presuming that because I have now specified a lifetime of 'a for the reference to ref_to_value, that mutable reference is now over the entire scope (ie. main). Whereas before, without the 'a lifetime reference, the mutable reference was limited?
I'm looking for clarity on how to think about this.
Your intuition is spot on. With one lifetime,
fn fill_object<'a>(m: &'a mut &'a u32, v: &'a u32) {
*m = v;
}
All three references are required to live for the same length, so if v lives a long time then the mutable reference must as well. This is not intuitive behavior, so it's generally a bad idea to tie together lifetimes like this. If you don't specify any lifetimes, Rust gives each reference a different one implicitly. So the following are equivalent.
fn fill_object(m: &mut &u32, v: &u32)
fn fill_object<'a, 'b, 'c>(m: &'a mut &'b u32, v: &'c u32)
(Note: The inferred lifetime of returned values is a bit more complicated but isn't in play here)
So, your partially-specified lifetimes are equivalent to
fn fill_object<'a>(m: &mut &'a u32, v: &'a u32);
fn fill_object<'a, 'b>(m: &'b mut &'a u32, v: &'a u32);
As a side note, &mut &u32 is a weird type for multiple reasons. Putting aside the fact that u32 is copy (and hence, outside of generics, useless to take immutable references of), a mutable reference to an immutable reference is just confusing. I'm not sure what you're real use case is. If this was just a test example, then sure. But if this is your real program, I recommend considering if you can get off with fill_object(&mut u32, u32), and if you really need the nested reference, you might consider making it a bit easier to swallow with a structure.
struct MyIntegerCell<'a>(&'a u32);
Plus some documentation as to why this is necessary. And then you would have fill_object(&mut MyIntegerCell, u32) or something like that.
Related
I was implementing linked lists by following along too many linked lists. When trying to implement iter_mut(), I did it myself and made the following code:
type Link<T> = Option<Box<Node<T>>>;
pub struct List<T> {
head: Link<T>,
}
struct Node<T> {
elem: T,
next: Link<T>,
}
impl<T> List<T> {
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut::<T>(&mut self.head)
}
}
pub struct IterMut<'a, T>(&'a mut Link<T>);
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = &'a mut T;
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.as_mut().map(|node| {
self.0 = &mut (**node).next;
&mut (**node).elem
})
}
}
I am to avoiding coersions and elisions because being explicit lets me understand more.
Error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/third.rs:24:16
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'b` as defined on the method body at 23:13...
--> src/third.rs:23:13
|
23 | fn next<'b>(&'b mut self) -> Option<&'a mut T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:24:9
|
24 | self.0.as_mut().map(|node| {
| ^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 20:6...
--> src/third.rs:20:6
|
20 | impl<'a, T> Iterator for IterMut<'a, T> {
| ^^
note: ...so that reference does not outlive borrowed content
--> src/third.rs:25:22
|
25 | self.0 = &mut (**node).next;
| ^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
I have looked at Cannot infer an appropriate lifetime for autoref due to conflicting requirements.
I understand a bit but not much. The problem that I am facing here is that if I try to change anything, an error pops saying that can't match the trait definition.
My thought was that basically I need to state somehow that lifetime 'b outlives 'a i.e <'b : 'a> but I can't figure out how to do it. Also, I have similar functions to implement iter() which works fine. It confuses me why iter_mut() produces such errors.
Iter
type Link<T> = Option<Box<Node<T>>>;
pub struct Iter<'a, T>(&'a Link<T>);
impl<'a, T> Iterator for Iter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.0.as_ref().map(|node| {
self.0 = &((**node).next);
&((**node).elem)
})
}
}
impl<T> List<T> {
pub fn iter(&self) -> Iter<T> {
Iter::<T>(&self.head)
}
}
☝️This works.
The key thing is that you need to be able to somehow extract an Option<&'a mut T> from a &'b mut IterMut<'a, T>.
To understand why IterMut<'a, T> := &'a mut Link<T> can't work, you need to understand what exactly you can do with a mutable reference. The answer, of course, is almost everything. You can copy data out of it, change its value, and lots of other things. The one thing you can't do is invalidate it. If you want to move the data under the mutable reference out, it has to be replaced with something of the same type (including lifetimes).
Inside the body of next, self is (essentially) &'b mut &'a mut Link<T>. Unless we know something about T (and we can't in this context), there's simply no way to produce something of type &'a mut Link<T> from this. For example, if this were possible in general, we'd be able to do
fn bad<'a, 'b, T>(_x: &'b mut &'a mut T) -> &'a mut T {
todo!()
}
fn do_stuff<'a>(x: &'a mut i32, y: &'a mut i32) {
// lots of stuff that only works if x and y don't alias
*x = 13;
*y = 42;
}
fn main() {
let mut x: &mut i32 = &mut 0;
let y: &mut i32 = {
let z: &mut &mut i32 = &mut x;
bad(z)
};
// `x` and `y` are aliasing mutable references
// and we can use both at once!
do_stuff(x, y);
}
(playground link)
The point is that if we were able to borrow something for a short (generic) lifetime 'b and return something that allowed modification during the longer lifetime 'a, we'd be able to use multiple short lifetimes (shorter than 'a and non-overlapping) to get multiple mutable references with the same lifetime 'a.
This also explains why the immutable version works. With immutable references, it's trivial to go from &'b &'a T to &'a T: just deference and copy the immutable reference. By contrast, mutable references don't implement Copy.
So if we can't produce a &'a mut Link<T> from a &'b mut &'a mut Link<T>, we certainly can't get an Option<&'a mut T out of it either (other than None). (Note that we can produce a &'b mut Link<T> and hence an Option<'b mut T>. That's what your code does right now.)
So what does work? Remember our goal is to be able to produce an Option<&'a mut T> from a &'b mut IterMut<'a, T>.
If we were able to produce a IterMut<'a, T> unconditionally, we'd be able to (temporarily) replace self with it and hence be able to directly access the IterMut<'a, T> associated to our list.
// This actually type-checks!
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = todo!(); // obviously this won't work
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.as_mut().map(|node| {
self.0 = &mut node.next;
&mut node.elem
})
}
(playground link)
The easiest way to set things up so that this all works is by transposing IterMut<'a, T> a bit. Rather than having the mutable reference outside the option, make it inside! Now you'll always be able to produce an IterMut<'a, T> with None!
struct IterMut<'a, T>(Option<&mut Box<Node<T>>>);
Translating next, we get
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
let mut temp: IterMut<'a, T> = IterMut(None);
std::mem::swap(&mut self.0, &mut temp.0);
temp.0.map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
More idiomatically, we can use Option::take rather than std::mem::swap (This is mentioned earlier in Too Many Linked Lists).
fn next<'b>(&'b mut self) -> Option<&'a mut T> {
self.0.take().map(|node| {
self.0 = node.next.as_mut();
&mut node.elem
})
}
(playground link)
This actually ends up being slightly different than the implementation in Too Many Linked Lists. That implementation removes the double indirection of &mut Box<Node<T>> and replaces it with simply &mut Node<T>. However, I'm not sure how much you gain since that implementation still has a double deref in List::iter_mut and Iterator::next.
Rust is trying to say that you have a dangling reference.
self.0.as_mut() // value borrowed
self.0 = <> // underlying value changed here.
The problem is the following definition:
pub struct IterMut<'a, T>(&'a mut Link<T>)
This can't encapsulate that you will have a "empty" node meaning reached the end of the node.
Use the structure as mentioned in the book like:
pub struct IterMut<'a, T>(Option<&'a mut Node<T>>);
This ensures that you can leave None in its place when you run end of list and use take to modify the IterMut content behind the scenes.
What is the reason the following code compiles fine, despite both the lifetimes 'a and 'b being independent of each other?
struct Foo<'a> {
i: &'a i32
}
fn func<'a, 'b>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
fn main() {}
If I make the reference i in Foo mutable, it gives the following error.
5 | fn func<'a, 'b>(x: &'a Foo<'b>) -> &'b i32 {
| ----------- -------
| |
| this parameter and the return type are declared with different lifetimes...
6 | x.i
| ^^^ ...but data from `x` is returned here
What is the reason it gives the above error?. Does it consider it's ownership over mutable reference and it sees that something (from Foo) is being taken out (with an independent lifetime), which is not possible, hence the error ?
This code (which I thought would pass) fails too:
struct Foo<'a> {
i: &'a mut i32
}
fn func<'a, 'b: 'a>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
fn main() {}
fails with error:
error[E0623]: lifetime mismatch
--> src/main.rs:6:5
|
5 | fn func<'a, 'b: 'a>(x: &'a Foo<'b>) -> &'b i32 {
| -----------
| |
| these two types are declared with different lifetimes...
6 | x.i
| ^^^ ...but data from `x` flows into `x` here
But this one passes:
struct Foo<'a> {
i: &'a mut i32
}
fn func<'a: 'b, 'b>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
fn main() {}
This seems a bit counter-intuitive to me. Here, the outer lifetime ('a) may outlive the inner lifetime ('b). Why is this not an error?
What is the reason the following code compiles fine, despite both the lifetimes 'a and 'b being independent of each other?
fn func<'a, 'b>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
The reason is that they are not independent of each other.
The type &'a Foo<'b> would be impossible if 'a outlived 'b. So, implicitly the Rust borrow-checker is inferring that you must have intended that 'b: 'a ('b outlives 'a). So the code above is semantically the same as this:
fn func<'a, 'b: 'a>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
If I make the reference i in Foo mutable, it gives the following error.
5 | fn func<'a, 'b>(x: &'a Foo<'b>) -> &'b i32 {
| ----------- -------
| |
| this parameter and the return type are declared with different lifetimes...
6 | x.i
| ^^^ ...but data from `x` is returned here
What is the reason it gives the above error?
When you pass around an immutable reference, it gets copied. In the above example, that means that the &'b i32 can be moved around by itself, and its liveness is not tied to where you got it from. This copied reference always points back to the original address of the data. And that's why the first example works - even if x was dropped, the original reference would still be valid.
When you pass around a mutable reference, it gets moved. A consequence of that is this case is that the reference is still "through" the variable x. If this wasn't the case, x's mutable reference to the contents of Foo could be live at the same time as this new immutable reference - which is not allowed. So, in this case the reference cannot outlive 'a - or put another way: 'a: 'b.
But didn't we already say 'b: 'a? The only conclusion here is that 'a and 'b must be the same lifetime, which is what your previous error message was demanding.
What is the reason it gives the above error?. Does it consider it's
ownership over mutable reference and it sees that something (from Foo)
is being taken out (with an independent lifetime), which is not
possible, hence the error ?
The mutable borrow indeed cannot be moved out of Foo since mutable borrows are not Copy. It is implicitly immutably reborrowed:
fn func <'a, 'b> (x:&'a Foo<'b>) -> &'b i32 {
&*x.i
}
However, this is not the source of the problem. First, here is a summary of the four versions of func (struct Foo has no relevance in my explanation):
version 1 (compiles):
fn func<'a, 'b>(x: &'a &'b i32) -> &'b i32 {
x
}
version 2 (fails to compile):
fn func<'a, 'b>(x: &'a &'b mut i32) -> &'b i32 {
x
}
version 3 (fails to compile):
fn func<'a, 'b: 'a>(x: &'a &'b mut i32) -> &'b i32 {
x
}
version 4 (compiles):
fn func<'a: 'b, 'b>(x: &'a &'b mut i32) -> &'b i32 {
x
}
Version 2 and 3 fail, because they violate the no-aliasing rule which forbids to have a mutable reference and an immutable reference to a resource at the same time. In both versions 'b may strictly outlive 'a. Therefore, &'b mut i32 and &'b i32 could coexist. Version 1 compiles, because the aliasing rules allow multiple immutable references to a resource at the same time. Therefore, &'b i32 may legally coexist with anothor &'b i32.
At first sight, it looks like version 4 should fail since there are again a mutable borrow and an immutable borrow of the same lifetime. The difference to version 2 and 3 is that this time 'a lives at least as long as 'b due to the requirement 'a: 'b, which implies that 'b may not strictly outlive 'a. As long as lifetime 'a lasts the referenced i32 cannot be mutably borrowed a second time (mutable references are not Copy) - the i32 is already mutably borrowed for the func call.
Here is an example demonstrating, how version 2 and 3 could lead to undefined behavior:
fn func<'a, 'b: 'a>(x: &'a &'b mut String) -> &'b str {
unsafe { std::mem::transmute(&**x as &str) } // force compilation
}
fn main() {
let mut s = String::from("s");
let mutref_s = &mut s;
let ref_s = {
let ref_mutref_s = &mutref_s;
func(ref_mutref_s)
};
// use the mutable reference to invalidate the string slice
mutref_s.clear();
mutref_s.shrink_to_fit();
// use the invalidated string slice
println!("{:?}", ref_s);
}
Swapping version 3 with version 4 shows how the in this case still active outer immutable borrow prevents the second mutable borrow. Lifetime 'a on the outer immutable borrow is forced by the new requirement 'a: 'b to be expanded to be equal to lifetime 'b:
error[E0502]: cannot borrow `*mutref_s` as mutable because `mutref_s` is also borrowed as immutable
--> src/main.rs:20:5
|
17 | let ref_mutref_s = &mutref_s;
| -------- immutable borrow occurs here
...
20 | mutref_s.clear();
| ^^^^^^^^ mutable borrow occurs here
...
23 | }
| - immutable borrow ends here
Just to add a suggestion (see the other answers for a detailed explanation of your question):
Whenever possible do not overdesign with lifetimes.
In this case being explicit about all lifetimes implies 4 cases (and quite a lot of thinking!).
Case 1 (compile)
fn func<'a, 'b: 'a>(x: &'a Foo<'b>) -> &'a i32 {
x.i
}
Case 2 (compile)
fn func<'a: 'b, 'b>(x: &'a Foo<'b>) -> &'a i32 {
x.i
}
Case 3 (compile)
fn func<'a: 'b, 'b>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
Case 4 (do not compile)
fn func<'a, 'b: 'a>(x: &'a Foo<'b>) -> &'b i32 {
x.i
}
If you use anonymous lifetimes and let the compiler build the dependencies between lifetime regions it is as simple as:
fn func<'a>(x: &'a Foo) -> &'a i32 {
x.i
}
Trying to compile this program I get stuck on the borrow checker:
use std::collections::BTreeMap;
type Object<'a> = BTreeMap<&'a str, i32>;
struct Root<'a>(Object<'a>);
struct Sub<'a>(&'a mut Object<'a>, &'a str);
impl<'a> Root<'a> {
fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
fn main() {
let mut me = Root(Object::new());
{
me.borrow_mut("data!");
}
me.borrow();
}
(Playground)
I get:
error[E0502]: cannot borrow `me` as immutable because it is also borrowed as mutable
--> src/main.rs:24:5
|
22 | me.borrow_mut("data!");
| -- mutable borrow occurs here
23 | }
24 | me.borrow();
| ^^ immutable borrow occurs here
25 | }
| - mutable borrow ends here
It looks like the mutable borrow should end before me.borrow() but the borrow checker insists that it ends when main ends.
To quickly explain what I'm trying to accomplish:
Make a parent struct to hold data
Make a sub category of data and store it in the parent
Use this builder style pattern to make MongoDB Queries
You are running afoul of a lifetime issue.
There are multiple different lifetimes in your program:
type Object<'a> = BTreeMap<&'a str, i32>; => this is one
&'a mut Object<'a> => there are up to TWO here
struct Sub<'a>(&'a mut Object<'a>, &'a str); => there are up to THREE here
There is, apparently, no reason for the reference to Object<'a> to have the same lifetime than the &str inside the BTreeMap. However, you told the compiler that you wanted both lifetimes to be the same!
When you write:
struct Sub<'a>(&'a mut Object<'a>, &'a str);
you are telling the compiler that:
the lifetime of the &str inside BTreeMap
the lifetime of the reference to Object<'_>
the lifetime of the &str accompanying the Object<'_>
are all one and the same.
You have over-constrained the requirements; and as a result no solution can satisfy them.
Adding one more degree of freedom is sufficient! We'll just make the lifetime of the reference to Object<'_> different from the lifetime of those &str floating around:
struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str);
impl<'b> Root<'b> {
fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
Note the subtle 'b: 'a:
Object<'b> contains a reference to something whose lifetime is 'b
the lifetime of the reference to Object<'b> (denoted 'a) must be SHORTER than 'b (otherwise you have a reference to something dead?)
Thus, we say that 'b outlives 'a with 'b: 'a.
And that's it. Simply loosening the requirements allow the compiler to allow your code to compile.
Note that in general, if you find yourself writing something like &'a &'a str you are doing it wrong. If you think about it, you will realize that in order to create a reference to something, it must first be. And therefore a reference to an object necessarily has a shorter lifetime than the object itself (ever so slightly).
I've got a vector of reference-counted RefCells and want to pass a Vec of (mut) references into the RefCells into a function. The references shouldn't need to outlive the function call.
It seems like it should be possible (with just one, something like &*x.borrow_mut() is ok). I tried to keep intermediate vectors of RefMut and &mut to control the lifetimes, but I haven't yet worked out a way to get it to work:
use std::cell::{RefCell,RefMut};
use std::vec::Vec;
use std::rc::Rc;
trait SomeTrait {}
struct Wrapper<'a> {
pub r: &'a mut SomeTrait,
}
fn foo(_: &[Wrapper]) {}
fn main() {
let mut v1: Vec<Rc<RefCell<SomeTrait>>> = unimplemented!();
let mut v_rm: Vec<RefMut<_>> = v1.iter_mut().map(|r| r.borrow_mut()).collect();
let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
foo(&v_wrapper[..]);
}
(playground)
There's clearly a lifetime issue:
rustc 1.11.0 (9b21dcd6a 2016-08-15)
error: borrowed value does not live long enough
--> <anon>:17:60
|>
17 |> let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
|> ^^^^^^^^^^
note: reference must be valid for the block suffix following statement 2 at 17:107...
--> <anon>:17:108
|>
17 |> let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
|> ^
note: ...but borrowed value is only valid for the block at 17:71
--> <anon>:17:72
|>
17 |> let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|ref mut rm| Wrapper{ r: &mut ***rm }).collect();
|> ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
I do control foo so can alter its API to make things easier, but it's in a different module/crate and I don't really want it to need to know that I keep my SomeTrait objects in an Rc<RefCell<_>>.
While it is certainly possible to write code that starts with a Vec<RefMut<T>> and creates a Vec<&mut T> from that (generic example), I would suggest that you change the signature of foo. Many algorithms do not need the random access provided by slices, and if the function could accept an iterator instead of a slice, you wouldn't need to create two whole additional Vecs, aside from the calling function becoming simpler. I'm thinking of a signature like this
fn foo<I, R>(widgets: I)
where I: IntoIterator<Item=R>,
R: DerefMut<Target=SomeTrait>
{
for widget in widgets {
// ...
}
}
Then all you need is producing an iterator that yields RefMut's, which is easily accomplished with v1.iter_mut().map(|x| x.borrow_mut()). Here's an example.
First, I agree with #delnan that you should switch to an iterator-based interface if you can.
Most of this code is just fine, and after changing foo and Wrapper to be a bit more flexible, I was able to tweak the rest and get it to compile:
use std::cell::{RefCell,RefMut};
use std::vec::Vec;
use std::rc::Rc;
trait SomeTrait {}
struct Wrapper<'a, 'b> where 'b: 'a {
pub r: &'a mut (SomeTrait + 'b),
}
fn foo<'a, 'b>(_: &'a mut [Wrapper<'a, 'b>]) where 'b: 'a {}
fn main() {
let mut v1: Vec<Rc<RefCell<SomeTrait>>> = unimplemented!();
let mut v_rm: Vec<RefMut<_>> = v1.iter_mut().map(|r| r.borrow_mut()).collect();
let mut v_wrapper: Vec<Wrapper> = v_rm.iter_mut().map(|mut rm| Wrapper{ r: &mut **rm }).collect();
foo(&mut v_wrapper[..]);
}
The key thing to understand here is that every trait object type has an implicit lifetime stapled to it, because an impl may contain references. There's no such type as SomeTrait, only SomeTrait + 'a or SomeTrait + 'b or SomeTrait + 'static.
The problem in your code was a mismatch between two things Rust inferred.
Where you wrote Rc<RefCell<SomeTrait>>, Rust assumed you meant Rc<RefCell<SomeTrait + 'static>>.
Where you wrote fn foo(_: &[Wrapper]) {}, different rules applied, and Rust assumed you meant fn foo<'a>(_: &'a [Wrapper<'a> + 'a]).
D'oh. Under those assumptions, the puzzle indeed has no solutions, and that's why I had to loosen things up.
If you don't want that 'b lifetime parameter, you can ditch it and just change 'b to 'static in the one place where it's used (on the type of Wrapper::r). That's less flexible: you'll be limited to SomeTrait impls that have static lifetime.
Trying to compile this program I get stuck on the borrow checker:
use std::collections::BTreeMap;
type Object<'a> = BTreeMap<&'a str, i32>;
struct Root<'a>(Object<'a>);
struct Sub<'a>(&'a mut Object<'a>, &'a str);
impl<'a> Root<'a> {
fn borrow_mut(&'a mut self, data: &'a str) -> Sub<'a> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
fn main() {
let mut me = Root(Object::new());
{
me.borrow_mut("data!");
}
me.borrow();
}
(Playground)
I get:
error[E0502]: cannot borrow `me` as immutable because it is also borrowed as mutable
--> src/main.rs:24:5
|
22 | me.borrow_mut("data!");
| -- mutable borrow occurs here
23 | }
24 | me.borrow();
| ^^ immutable borrow occurs here
25 | }
| - mutable borrow ends here
It looks like the mutable borrow should end before me.borrow() but the borrow checker insists that it ends when main ends.
To quickly explain what I'm trying to accomplish:
Make a parent struct to hold data
Make a sub category of data and store it in the parent
Use this builder style pattern to make MongoDB Queries
You are running afoul of a lifetime issue.
There are multiple different lifetimes in your program:
type Object<'a> = BTreeMap<&'a str, i32>; => this is one
&'a mut Object<'a> => there are up to TWO here
struct Sub<'a>(&'a mut Object<'a>, &'a str); => there are up to THREE here
There is, apparently, no reason for the reference to Object<'a> to have the same lifetime than the &str inside the BTreeMap. However, you told the compiler that you wanted both lifetimes to be the same!
When you write:
struct Sub<'a>(&'a mut Object<'a>, &'a str);
you are telling the compiler that:
the lifetime of the &str inside BTreeMap
the lifetime of the reference to Object<'_>
the lifetime of the &str accompanying the Object<'_>
are all one and the same.
You have over-constrained the requirements; and as a result no solution can satisfy them.
Adding one more degree of freedom is sufficient! We'll just make the lifetime of the reference to Object<'_> different from the lifetime of those &str floating around:
struct Sub<'a, 'b: 'a>(&'a mut Object<'b>, &'b str);
impl<'b> Root<'b> {
fn borrow_mut<'a>(&'a mut self, data: &'b str) -> Sub<'a, 'b> {
Sub(&mut self.0, data)
}
fn borrow(&self) {
println!("{:?}", self.0);
}
}
Note the subtle 'b: 'a:
Object<'b> contains a reference to something whose lifetime is 'b
the lifetime of the reference to Object<'b> (denoted 'a) must be SHORTER than 'b (otherwise you have a reference to something dead?)
Thus, we say that 'b outlives 'a with 'b: 'a.
And that's it. Simply loosening the requirements allow the compiler to allow your code to compile.
Note that in general, if you find yourself writing something like &'a &'a str you are doing it wrong. If you think about it, you will realize that in order to create a reference to something, it must first be. And therefore a reference to an object necessarily has a shorter lifetime than the object itself (ever so slightly).