So, I have the following problem. I have a structure implementation, and one of the methods of this structure consumes the instance of the structure, which is ok by me, as it is literally the last thing I want to do in my program with this instance (my_struct), but it's totally not OK with the borrow checker:
use std::thread;
struct MyStruct {
some_field: Vec<String>
}
impl MyStruct {
fn new() -> Self {
MyStruct {
some_field: vec!("str".to_string())
}
}
fn do_something_with_self_in_thread(&'static mut self) {
thread::spawn(move || self.some_field = vec!("another_str".to_string()));
}
}
fn main() {
let my_struct: &'static mut MyStruct = &mut MyStruct::new();
my_struct.do_something_with_self_in_thread()
// Some blocking call will follow
}
Error:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:20:49
|
20 | let my_struct: &'static mut MyStruct = &mut MyStruct::new();
| --------------------- ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
21 | my_struct.do_something_with_self_in_thread()
22 | }
| - temporary value is freed at the end of this statement
For more information about this error, try `rustc --explain E0716`.
I tried playing around with lifetimes, but resultless.
How do I get myself out of this situation?
Playground link
When we say a method consumes the instance, then it should take self and not a mutable borrow &mut self in the definition.
i.e.
impl MyStruct {
...
fn do_something_with_self_in_thread(self) {
...
}
}
As commenters have already said, your second problem is with lifetimes. The compiler can't reason about references not outliving owners of resources if they are in separate threads. So to this end the thread::spawn method has trait bounds requiring that the closure is 'static, which means the variables it captures can live as long as they like. Examples which are valid would be owned types T, not references &T or &mut T, unless they are &'static T types. That's not the case in your code as you've instantiated a struct inside main (albeit erroneously annotated as having a 'static lifetime) and then tried to move a mutable borrow of a field inside your closure.
Related
tl;dr given pub fn func(&'a mut self), why is self considered "mutably borrowed" after func has run?
Given the following minimal viable example (playground)
pub struct Struct1<'a> {
var: &'a u8,
}
impl<'a> Struct1<'a> {
pub fn new() -> Struct1<'a> {
return Struct1 {
var: &33,
}
}
pub fn func(&'a mut self) -> () {
()
}
}
fn main() {
let mut s1 = Struct1::new();
s1.func(); // point 1
// point 2
s1.func(); // point 3
}
results in compiler error
error[E0499]: cannot borrow `s1` as mutable more than once at a time
--> src/test12-borrow-mut-struct-twice-okay.rs:20:5
|
18 | s1.func(); // point 1
| -- first mutable borrow occurs here
19 | // point 2
20 | s1.func(); // point 3
| ^^
| |
| second mutable borrow occurs here
| first borrow later used here
However, at // point 2 the s1 appears to me to not be anymore borrowed. The func is done running. What could be still be borrowing self within func!? It appears func at //point 1 has relinquished control of s1.
What is still borrowing s1 at // point 3 ?
Similar questions:
borrow-errors-for-multiple-borrows
returning-a-reference-from-a-hashmap-or-vec-causes-a-borrow-to-last-beyond-the-s
mysterious-borrow-scope-extension
cannot-borrow-variable-when-borrower-scope-ends
why-does-this-mutable-borrow-live-beyond-its-scope)
mutable-borrow-seems-to-outlive-its-scope
What is still borrowing s1 at // point 3 ?
You're telling the compiler that it's still borrowed, so it's trusting you: while the compiler verifies that your lifetimes are not too short, it doesn't really care if they're so long they make things unusable.
When you write &'a mut self, the 'a is the one declared on the impl block, and thus the one defined on the struct. &'a mut self literally desugars to:
self: &'a mut Struct1<'a>
so once you've called func() the rust compiler goes "well this is borrowed for 'a which is the lifetime associated with s1 which is 'static, so this is mutably borrowed forever, good day", and thus you get "locked out" of the structure.
In fact you can see this aliasing by trying to explicitly declare an 'a on func:
pub fn func<'a>(&'a mut self) -> () {
()
}
error[E0496]: lifetime name `'a` shadows a lifetime name that is already in scope
--> src/main.rs:11:17
|
5 | impl<'a> Struct1<'a> {
| -- first declared here
...
11 | pub fn func<'a>(&'a mut self) -> () {
| ^^ lifetime `'a` already in scope
error: aborting due to previous error
So rust is telling you in no uncertain term that within the block 'a always refers to the lifetime declared on the impl block.
The solution is to just remove the 'a, that's the wrong lifetime entirely:
pub fn func(&mut self) -> () {
()
}
In that case rustc will automatically introduce a lifetime, and since the function is not actually borrowing anything that lifetime will only extend to the function call.
I'm trying to put a borrowed value behind a Mutex but I'm having trouble with the borrow checker. Here's a simplified code that demonstrate the problem I encounter:
use std::{
marker::PhantomData,
sync::{Arc, Mutex},
};
struct Test<'a> {
d: PhantomData<Mutex<&'a u8>>,
}
impl<'a> Test<'a> {
pub fn new() -> Self {
Test { d: PhantomData }
}
pub fn test(&'a self) {}
}
fn main() {
let t = Arc::new(Test::new());
let t2 = t.clone();
std::thread::spawn(move || {
t2.test();
});
}
This fails to compile with the following error
error[E0597]: `t2` does not live long enough
--> src/main.rs:21:9
|
19 | let t2 = t.clone();
| -- lifetime `'1` appears in the type of `t2`
20 | std::thread::spawn(move || {
21 | t2.test();
| ^^-------
| |
| borrowed value does not live long enough
| argument requires that `t2` is borrowed for `'1`
22 | });
| - `t2` dropped here while still borrowed
I guess the compiler thinks t2 might be borrowed to somewhere else when calling test(). It seems if I modify the type of the d field in struct Test to anything excluding Mutex, such as d: Option<&'a u8>, it works fine. What is so special about Mutex since it's just a wrapper around an UnsafeCell?
What is so special about Mutex since it's just a wrapper around an UnsafeCell?
The difference is variance.
&'a T is covariant in the lifetime 'a: You can coerce an immutable reference with a longer lifetime to one with a strictly shorter lifetime, because it is always safe to pass &'long T where &'short T is expected. This is why the code compiles without the UnsafeCell.
But UnsafeCell<&'a T> is invariant in 'a because it has interior mutability: If you could pass UnsafeCell<&'long T> to code that takes UnsafeCell<&'short T>, that code could write a short-lived reference into your long-lived cell. So it is not safe to coerce an UnsafeCell to have a different lifetime.
(The same is true for any type that lets you mutate the reference it contains, e.g. Mutex<&'a T> or &mut &'a T.)
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 am having some trouble with the dynamic dispatch pointer types in Rust. I want to convert a value of type Box<MyTrait> to &mut MyTrait to pass to a function. For example, I tried:
use std::borrow::BorrowMut;
trait MyTrait {
fn say_hi(&mut self);
}
struct MyStruct { }
impl MyTrait for MyStruct {
fn say_hi(&mut self) {
println!("hi");
}
}
fn invoke_from_ref(value: &mut MyTrait) {
value.say_hi();
}
fn main() {
let mut boxed_trait: Box<MyTrait> = Box::new(MyStruct {});
invoke_from_ref(boxed_trait.borrow_mut());
}
This fails with the following error:
error: `boxed_trait` does not live long enough
--> <anon>:22:5
|
21 | invoke_from_ref(boxed_trait.borrow_mut());
| ----------- borrow occurs here
22 | }
| ^ `boxed_trait` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
Strangely enough, this works for &MyTrait but not for &mut MyTrait. Is there any way I can get this conversion to work in the mutable case?
I think you're running into a limitation of the current compiler's lifetime handling. borrow_mut, being a function, imposes stricter lifetime requirements than necessary.
Instead, you can take a mutable borrow to the box's interior by first dereferencing the box, like this:
fn main() {
let mut boxed_trait: Box<MyTrait> = Box::new(MyStruct {});
invoke_from_ref(&mut *boxed_trait);
}
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).