Lifetimes in async Rust

I have combed through a litany of Reddit posts, Github issues, and posts on this forum trying to understand the lifetimes associated with async Rust, and I've consulted a great many LLMs but to no avail.

use std::path::PathBuf;

fn serialize_response<'a>(serializer: SerializerType, producer: &'a mut producer::Producer<'a>) {
    println!("{}", serializer);
}

#[tokio::main]
async fn main() {
    let conf = producer::ProducerConf {
        base_dir: PathBuf::from(".")
    };
    let mut producer: producer::Producer = producer::Producer::new(conf).unwrap();
    let serializer = SerializerType::A;

    match serializer {
        SerializerType::A => {
            serialize_response(serializer, &mut producer);
        }
        SerializerType::B => {
            serialize_response(serializer, &mut producer);
        }
        _ => {}
    }
}

I have a code block like the above following, where cargo check gives an error at &mut producer. serialize_response takes in a mutable borrow and is a synchronous function.

error[E0597]: `producer` does not live long enough
  --> src/main.rs:67:9
   |
49 |     let mut producer: producer::Produc...
   |         ------------ binding `producer` declared here
...
67 |         &mut producer,
   |         ^^^^^^^^^^^^^ borrowed value does not live long enough
...
71 | }
   | -
   | |
   | `producer` dropped here while still borrowed
   | borrow might be used here, when `producer` is dropped and runs the destructor for type `Producer<'_>`

For more information about this error, try `rustc --explain E0597`.

How do I solve this problem? I have tried Arc, explored mspc channels, and async closures on nightly rust, but I wasn't able to quite get any of them to work (I'm sure due to my own misunderstandings).

This seems pretty simple to me but as a beginner seems needlessly difficult. As I understand it, it's because my Producer struct takes in an explicit lifetime parameter, which is the scope of when it's created, so the scope of main(). My serialize_response() thereby assumes the same lifetime explicitly by requiring producer as an argument. But is it because main() is async that the result of the function, being a future, may exceed the lifetime of the producer? How should I go about this simple example?

pub fn serialize_response<'a>(
    serializer_type: SerializerType,
    producer: &'a mut producer::Producer<'a>,
)

I apologize if this question is derivative of existing questions, but I am unable to infer based on past responses.

Thank you for your time.

We don't have to look further than this. &'a mut T<'a> is a classic antipattern. Because T is invariant behind a mutable reference, &'a mut T<'a> creates something that is borrowed for its whole lifetime, rendering it basically useless.

Also, it would be really helpful if you could provide us with a minimal reproducible example, preferably with a link to it on the playground. Without the knowing what Producer looks like, it is hard to understand what you are trying to do.

7 Likes

Thank you, I don't think I would have discovered that on my own. Noted about the Playground.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.