5

I thought that I've got what the 'static lifetime is, but now I'm not sure.

I'm trying to understand how to work with Tokio and Futures. My app is working, but the structure is awful, so I need to decompose it. Here comes 'static requirement for my closures, that I don't know how to resolve.

For example, in a main function I have a handle and able to spawn a future to its loop:

let mut core = tokio_core::reactor::Core::new().unwrap();
let handle = core.handle();
let future = {
    ok(())
};

It compiles; now I want to move some logic out:

struct Test;
impl Test {
    fn test(&self, handle: tokio_core::reactor::Handle) {
        let future = {
            ok(())
        };
        handle.spawn(future);
    }
}

It compiles too. When my struct gets more complicated:

struct Test<'a> {
    api: &'a Arc<Api>,
}

impl<'a> Test<'a> {
    fn new(api: &'a Arc<Api>) -> Self {
        Test {
            api: api,
        }
    }

    fn test(&self, msg: &telegram_bot::types::Message, handle: tokio_core::reactor::Handle) {
        let api = self.api.clone();
        let future = ok(10);
        let future2 = move |x| {
            api.send(msg.text_reply(format!("reply: {}", x))) // returns Future
        }.map(|_| ()).map_err(|_| ()); // let's ignore the results for now
        handle.spawn(future.and_then(future2));
    }
}

... I run into

error[E0477]: the type `futures::AndThen<futures::FutureResult<i32, ()>, futures::FutureResult<(), ()>, [closure@src/main.rs:63:23: 66:10 api:std::sync::Arc<telegram_bot::Api>, msg:&telegram_bot::Message]>` does not fulfill the required lifetime
handle.spawn(future.and_then(future2));
       ^^^^^
note: type must satisfy the static lifetime

I think it yells about my closure. The same future works if I have it in the main function with my Arc'ed Api.

Moving this to a struct with references like a separate "processor" break it with 'static errors.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
fevgenym
  • 568
  • 7
  • 20
  • *I thought that I've got what the 'static lifetime is* — what did you think it was? Why do you think that `api` has the `'static` lifetime? – Shepmaster Jan 29 '18 at 15:32
  • @Shepmaster, I thought that `'static` lifetime is used to indicate data which is placed in `.bss` sector, like string literals known in compile time. I'm not sure that `api` has the `'static` lifetime, but I see in docs that `spawn` method needs this lifetime for it's argument. I don't know why it is `'static` in `main` function, where there are no errors. – fevgenym Jan 29 '18 at 15:44
  • `fn spawn(&self, f: F) where F: Future + 'static ` I mean – fevgenym Jan 29 '18 at 15:47
  • 16
    TL;DR the duplicates: the `'static` *bound* on a generic type requires that any references inside the type must live as least as long as `'static`. If your type has no references, it meets the bounds. If it has references, they must be `'static`. – Shepmaster Jan 29 '18 at 15:51
  • @Shepmaster, oh, I got it, thank you. If I set the reference to `msg` to `'static` it compiles, but it won't clean old messages, right? – fevgenym Jan 29 '18 at 16:00
  • 3
    Do you mean `fn test(&self, msg: &'static Message, handle: Handle)`? If so, then you will only be able to pass in `Message`s that live for the entire life of the program (which is probably not what you want). Instead, you should probably just take in a `Message` by value and move it into the closure / future. In that case, you will have no lifetimes, thus you will meet the `'static` bounds. I'd also recommend storing just an `Arc` in your `Test`, not a `&'a Arc`. – Shepmaster Jan 29 '18 at 16:06
  • Suddenly it became totally clear for me. Thank you very much, @Shepmaster, for your work for the community. – fevgenym Jan 29 '18 at 16:20
  • You are very welcome! I hope you enjoy working with Rust as much as we do! – Shepmaster Jan 29 '18 at 16:21

0 Answers0