Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
754 views
in Technique[技术] by (71.8m points)

asynchronous - Confused about variable lifetime in tokio::spawn(async move

I am new to rust and tokio async, and I am trying to compile the following seemingly straightforward code:

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?
}

But the compiler complains:

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 {
   |     ^^^^^^^^^^^^^^^^^

From the previous discussions and examples I have found on the subject, I understand that passing a reference to network_config to the spawn-ed closure would cause lifetime problems since the separate thread may outlive network_config. This is why I am moving a clone of network_config to the spawned thread, but there still seems to be a lifetime ambiguity.

Is there any extra hint I could give the compiler so that it correctly gets the lifetimes ? Or am I doing the whole thing wrong ?

Note: the NetworkConfig class is defined as:

#[derive(Debug, Deserialize)]
pub struct NetworkConfig {
    pub bind: String,
    pub node_key_file: String,
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you want clone the NetworkConfig value declare for it the Clone trait:

#[derive(Debug, Clone)]
pub struct NetworkConfig {
    pub bind: String,
    pub node_key_file: String,
}

Otherwise, for the rules of receiver method lookup you will end up with invoking a Clone on a reference through the following Clone implementer:

impl<'_, T> Clone for &'_ T

And the cloned reference will have a lifetime bound to scope of clone() invocation.

With derive(Clone) the run function compiles, but it works only when network_config argument has 'static lifetime, because of tokio::spawn lifetime requirement.

Probably this is not what you want. If this is the case pass NetworkConfig by value and eventually clone it in the caller context.

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

You may ask why this works, indeed a reference is still passed to network_handler().

This is because network_config is moved inside the spawn async block and this makes gaining static lifetime for the inferred type of the async block.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...