tokio::select!中的临时值宏



我想我对临时对象、它们的生存期和对它们的引用有一些了解。但是我不明白下面这种情况是怎么回事:

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(())
}

编译器告诉我们,在第10行select!宏的末尾释放临时变量。临时变量只能由select!宏中的receive方法借用。在select!宏之后,我们立即从函数返回。没有更多的借款了。这种情况下出了什么问题?这个信息"借用"了什么,后来被"闭包"捕捉到了?的意思吗?

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

我可以通过为临时变量引入局部变量来解决这个问题。问题更多的是问题出在哪里,而不是如何解决问题。我想我还没有完全理解Rust的概念。

您可以查看使用cargo expand生成的代码。在这里,您可以看到宏的手臂是在future中捕获的。

我添加了一个最小的例子,在代码中显示类似的情况,没有使用宏。在这个例子中,awaitfuture上被调用,但是编译器的错误信息是一样的。

Signal不能被删除,因为future仍然有一个引用指向它。

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(())
}

编译错误

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

最新更新