I have a struct:
struct MyData {
    x: i32
}
I want to asynchronously start a long operation on this struct.
My first attempt was this:
fn foo(&self) { //should return immediately
    std::thread::Thread::spawn(move || { 
        println!("{:?}",self.x); //consider a very long operation
    });
}
Clearly the compiler cannot infer an appropriate lifetime due to conflicting requirements because self may be on the stack frame and thus cannot be guaranteed to exist by the time the operation is running on a different stack frame.
To solve this, I attempted to make a copy of self and provide that copy to the new thread:
fn foo(&self) { //should return immediately
    let clone = self.clone();
    std::thread::Thread::spawn(move || { 
        println!("{:?}",clone.x); //consider a very long operation
    });
}
I think that does not compile because now clone is on the stack frame which is similar to before.  I also tried to do the clone inside the thread, and that does not compile either, I think for similar reasons.
Then I decided maybe I could use a channel to push the copied data into the thread, on the theory that perhaps channel can magically move (copy?) stack-allocated data between threads, which is suggested by this example in the documentation.  However the compiler cannot infer a lifetime for this either:
fn foo(&self) { //should return immediately
    let (tx, rx) = std::sync::mpsc::channel();
    tx.send(self.clone());
    std::thread::Thread::spawn(move || { 
        println!("{:?}",rx.recv().unwrap().x); //consider a very long operation
    });
}
Finally, I decided to just copy my struct onto the heap explicitly, and pass an Arc into the thread. But not even here can the compiler figure out a lifetime:
fn foo(&self) { //should return immediately
    let arc = std::sync::Arc::new(self.clone());
    std::thread::Thread::spawn(move || { 
        println!("{:?}",arc.clone().x); //consider a very long operation
    });
}
Okay borrow checker, I give up.  How do I get a copy of self onto my new thread?
I think your issue is simply because your structure does not derive the Clone trait. You can get your second example to compile and run by adding a #[derive(Clone)] before your struct's definition.
What I don't understand in the compiler behaviour here is what .clone() function it tried to use here. Your structure indeed did not implement the Clone trait so should not by default have a .clone() function.
playpen
You may also want to consider in your function taking self by value, and let your caller decide whether it should make a clone, or just a move.
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