简体   繁体   中英

Temporary values in tokio::select! macro

I think I have some understanding of temporaries, their lifetimes and references to them. But I don't understand what's wrong in the following situation:

use std::io;

use tokio::signal::unix::{self, SignalKind};

#[tokio::main]
async fn main() -> io::Result<()> {
    tokio::select! {
        _ = unix::signal(SignalKind::interrupt())?.recv() => (),
        _ = unix::signal(SignalKind::terminate())?.recv() => (),
    }

    Ok(())
}

As the compiler tells us, the temporaries are freed at the end of the select! macro in line 10. The temporaries are borrowed only by the receive methods within the select! macro. After the select! macro, we immediately return from the function. There are no further borrows. What is wrong in this situation? And what does the message "borrow later captured here by closure" mean?

error[E0716]: temporary value dropped while borrowed
  --> routing_server/src/main.rs:9:13
   |
7  | /     tokio::select! {
8  | |         _ = unix::signal(SignalKind::interrupt())?.recv() => (),
9  | |         _ = unix::signal(SignalKind::terminate())?.recv() => (),
   | |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
10 | |     }
   | |     -
   | |     |
   | |_____temporary value is freed at the end of this statement
   |       borrow later captured here by closure
   |
   = note: consider using a `let` binding to create a longer lived value

I can fix the situation by introducing local variables for the temporaries. The question is more about what's the problem rather than how to fix it. I think I haven't fully understood Rust's concepts yet.

You can look at the code generated by using cargo expand . Here you see that the arm of the macro is captured in a future .

I have added a minimal example showing a similar situation in code, without the usage of the macro. In this example await is called on the future , but the compiler error message is the same.

Signal cannot be dropped because a future still has a reference pointing to it.

Example

    use std::error::Error;
    
    struct Signal {}
    
    impl Signal {
        async fn recv(&mut self) -> () {
            ()
        }
    }
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn Error>>  {
        // tokio::select! {
        //     _ = Signal {}.recv() => (),
        // }
        let future = Signal {}.recv();
        future.await;
        
        Ok(())
    }

Compiler Error

    16 |     let future = Signal {}.recv();
       |                  ^^^^^^^^^       - temporary value is freed at the end of this statement
       |                  |
       |                  creates a temporary which is freed while still in use
    17 |     future.await;
       |     ------ borrow later used here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM