0

I'm new to Rust, and trying to learn the language by creating something around it.

Facing this problem that the self is valid inside this function but the closure is async so it may be executed after the lifetime of this function and that closure captures self. I get the problem. But what should I do? I understand that it is something to do with the lifetimes. But can someone point to me what the solution is?

pub async fn run(&mut self) -> Result<i32, &str> {
    .
    .
    .

    match server.accept().await {
        Ok(p) => {
            tokio::spawn(async {
                self.handle_temp_connection(p)
            });
        },
        Err(err) => {
            println!("Some problem accepting a connection.")
        }
    }
}

fn handle_temp_connection(&self, p_socket_addr: (TcpStream, SocketAddr)) {
    ...
}

Error:

error[E0521]: borrowed data escapes outside of associated function
  --> src/app.rs:34:21
   |
20 |       pub async fn run(&mut self) -> Result<i32, &str> {
   |                        ---------
   |                        |
   |                        `self` is a reference that is only valid in the associated function body
   |                        let's call the lifetime of this reference `'1`
...
34 | /                     tokio::spawn(async {
35 | |                         self.handle_temp_connection(p)
36 | |                     });
   | |                      ^
   | |                      |
   | |______________________`self` escapes the associated function body here
   |                        argument requires that `'1` must outlive `'static`
bradley101
  • 723
  • 6
  • 19
  • You won't be able to pass `self` along to a thread unless you're prepared to hand over ownership as well. References will not work. Could this be `pub async fn run (self) ...`? – tadman Jul 25 '23 at 20:06
  • Okay so what should I do in this case? I want to handle that connection in a another function. – bradley101 Jul 25 '23 at 20:07
  • That's fine so long as you can hand over ownership. This is where using channels to communicate back any results might help. – tadman Jul 25 '23 at 20:08
  • Above that `match` there is `let server = self.server.as_ref.unwrap()` So If I use `self` in the function declaration, `self.server` would consume the `self` and I would not be able to use it afterwards. – bradley101 Jul 25 '23 at 20:16
  • So how does production code deal with this problem? Its a general thing I guess, to invoke a thread that can use the caller's self members? How do you achieve it? – bradley101 Jul 25 '23 at 20:17
  • 1
    Personally I just architect so that the `self` in question is self-contained and can be delegated, as in handed off entirely. This typically means having a handler per connection rather than a handler for all connections. – tadman Jul 25 '23 at 20:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254662/discussion-between-bradley101-and-tadman). – bradley101 Jul 25 '23 at 20:33

1 Answers1

0

I'm going to assume that handle_temp_connection is supposed to be an async function. If it's not, you should use tokio::spawn_blocking, but most of the rest still applies.

If you only need to call run once and nothing else on self later, then you can have it take ownership and give ownership to handle_temp_connection.

pub async fn run(self)
...
tokio::spawn(self.handle_temp_connection(p));
...
async fn handle_temp_connection(self, p_socket_addr: (TcpStream, SocketAddr))

If you need self after calling run, you can still pass ownership to handle_temp_connection, but after cloning it.

tokio::spawn(self.clone().handle_temp_connection(p));

If you use an async block here, you will need to clone it first into another variable and then async move that variable into the block.

If you want some shared state between the self in run and the self in handle_temp_connection, then you can use Arc like in this question.

Another thing you can do is rewrite handle_temp_connection to not use self.

tokio::spawn(handle_temp_connection(p));

If you need some information from self, you can clone parts of self and pass them to handle_temp_connection as arguments.

drewtato
  • 6,783
  • 1
  • 12
  • 17