-1

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

kek_mek
  • 105
  • 4
  • I mean, I understand that when I say that the instance of the structure is `'static`, I give a pinky promise that it should live for as long as the program runs, but if I get rid of this `'static` now - then the compiles starts demanding it – kek_mek Jul 15 '22 at 15:35
  • 1
    You have several problems with that example, like how nothing owns anything, leading to the "temporary value" errors. You also can't borrow across a thread boundary, because you don't know what may happen to the thread. Can you elaborate on what you expect to happen here? – Jeremy Meadows Jul 15 '22 at 15:44
  • 1
    _"I give a pinky promise"_ That's not how things work. Lifetimes are descriptive, not prescriptive. In that case, any borrow of that struct value can never fulfill that lifetime. Most likely, you want to move the whole value into the closure. This is akin to the problem of trying to [return a reference from a local value](https://stackoverflow.com/questions/32682876/is-there-any-way-to-return-a-reference-to-a-variable-created-in-a-function). – E_net4 Jul 15 '22 at 15:49
  • Usually, I will ask "why do I have to write code that way?" Are there alternatives? The Borrow Checker is there to help us doing stuff that might cause unexpected results – Thai Anh Duc Jul 16 '22 at 01:14
  • Thank you everybody for reassuring me that I am doing something fundamentally wrong, your comments lead me to a much better approach where I call the entire function in a separate thread, delegating the ownership of everything to the thread span. Both create the instance of the struct and call the methods on it. – kek_mek Jul 18 '22 at 08:08

1 Answers1

1

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.

jsstuball
  • 4,104
  • 7
  • 33
  • 63