对 tokio::spawn 中的变量生命周期感到困惑(异步移动
Confused about variable lifetime in tokio::spawn(async move
我是 rust 和 tokio async 的新手,我正在尝试编译以下看似简单的代码:
async fn network_handler(network_config: &config::NetworkConfig) -> Result<(), Error> {
Ok(())
}
pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
let network_config_copy = network_config.clone();
tokio::spawn(async move {
network_handler(&network_config_copy).await
}).await?
}
但是编译器抱怨:
error: cannot infer an appropriate lifetime
--> src/network.rs:43:18
|
43 | pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
| ^^^^^^^^^^^^^^ ...but this borrow...
44 | let network_config_copy = network_config.clone();
45 | tokio::spawn(async move {
| ------------ this return type evaluates to the `'static` lifetime...
|
note: ...can't outlive the lifetime `'_` as defined on the function body at 43:34
--> src/network.rs:43:34
|
43 | pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the function body at 43:34
|
45 | tokio::spawn + '_(async move {
| ^^^^^^^^^^^^^^^^^
根据之前关于该主题的讨论和示例,我了解到将对 network_config 的引用传递给 spawn-ed 闭包会导致生命周期问题,因为单独的线程可能比 network_config.
这就是为什么我要将 network_config 的克隆移动到生成的线程,但似乎仍然存在生命周期的歧义。
是否有任何额外的提示我可以给编译器以使其正确获取生命周期?还是我整件事都做错了?
注意:NetworkConfig class 定义为:
#[derive(Debug, Deserialize)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
如果要克隆 NetworkConfig
值,请为其声明 Clone
特征:
#[derive(Debug, Clone)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
否则,对于接收方方法查找的规则,您最终将通过以下方式在引用上调用 Clone
以下 Clone
implementer:
impl<'_, T> Clone for &'_ T
并且克隆引用的生命周期将绑定到 clone()
调用范围。
使用 derive(Clone)
时,run
函数可以编译,但它仅在 network_config
参数具有 'static
时有效
生命周期,因为 tokio::spawn 生命周期要求。
这可能不是您想要的。如果是这种情况,按值传递 NetworkConfig
并最终将其克隆到调用者中
语境。
use async_std::io::Error;
use tokio;
mod config {
#[derive(Debug, Clone)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
}
async fn network_handler(network_config: &config::NetworkConfig) -> Result<(), Error> {
println!("using {:?}", network_config);
Ok(())
}
pub async fn run(network_config: config::NetworkConfig) -> Result<(), Error> {
tokio::spawn(async move { network_handler(&network_config).await }).await?
}
#[tokio::main]
async fn main() {
let config = config::NetworkConfig {
bind: "my_bind".to_owned(),
node_key_file: "abc".to_owned(),
};
tokio::spawn(run(config.clone()));
}
您可能会问为什么这有效,实际上仍然将引用传递给 network_handler()
。
这是因为 network_config
被移动到 spawn 异步块中并且
这使得异步块的推断类型获得静态生命周期。
我是 rust 和 tokio async 的新手,我正在尝试编译以下看似简单的代码:
async fn network_handler(network_config: &config::NetworkConfig) -> Result<(), Error> {
Ok(())
}
pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
let network_config_copy = network_config.clone();
tokio::spawn(async move {
network_handler(&network_config_copy).await
}).await?
}
但是编译器抱怨:
error: cannot infer an appropriate lifetime
--> src/network.rs:43:18
|
43 | pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
| ^^^^^^^^^^^^^^ ...but this borrow...
44 | let network_config_copy = network_config.clone();
45 | tokio::spawn(async move {
| ------------ this return type evaluates to the `'static` lifetime...
|
note: ...can't outlive the lifetime `'_` as defined on the function body at 43:34
--> src/network.rs:43:34
|
43 | pub async fn run(network_config: &config::NetworkConfig) -> Result<(), Error> {
| ^
help: you can add a constraint to the return type to make it last less than `'static` and match the lifetime `'_` as defined on the function body at 43:34
|
45 | tokio::spawn + '_(async move {
| ^^^^^^^^^^^^^^^^^
根据之前关于该主题的讨论和示例,我了解到将对 network_config 的引用传递给 spawn-ed 闭包会导致生命周期问题,因为单独的线程可能比 network_config. 这就是为什么我要将 network_config 的克隆移动到生成的线程,但似乎仍然存在生命周期的歧义。
是否有任何额外的提示我可以给编译器以使其正确获取生命周期?还是我整件事都做错了?
注意:NetworkConfig class 定义为:
#[derive(Debug, Deserialize)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
如果要克隆 NetworkConfig
值,请为其声明 Clone
特征:
#[derive(Debug, Clone)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
否则,对于接收方方法查找的规则,您最终将通过以下方式在引用上调用 Clone
以下 Clone
implementer:
impl<'_, T> Clone for &'_ T
并且克隆引用的生命周期将绑定到 clone()
调用范围。
使用 derive(Clone)
时,run
函数可以编译,但它仅在 network_config
参数具有 'static
时有效
生命周期,因为 tokio::spawn 生命周期要求。
这可能不是您想要的。如果是这种情况,按值传递 NetworkConfig
并最终将其克隆到调用者中
语境。
use async_std::io::Error;
use tokio;
mod config {
#[derive(Debug, Clone)]
pub struct NetworkConfig {
pub bind: String,
pub node_key_file: String,
}
}
async fn network_handler(network_config: &config::NetworkConfig) -> Result<(), Error> {
println!("using {:?}", network_config);
Ok(())
}
pub async fn run(network_config: config::NetworkConfig) -> Result<(), Error> {
tokio::spawn(async move { network_handler(&network_config).await }).await?
}
#[tokio::main]
async fn main() {
let config = config::NetworkConfig {
bind: "my_bind".to_owned(),
node_key_file: "abc".to_owned(),
};
tokio::spawn(run(config.clone()));
}
您可能会问为什么这有效,实际上仍然将引用传递给 network_handler()
。
这是因为 network_config
被移动到 spawn 异步块中并且
这使得异步块的推断类型获得静态生命周期。