1

I have a struct that should be inited once with some value and then it can be freely referenced (or even shared across threads) without problems. The problem is that I want to use it in a handler of hyper callback. Here is my sample code:

extern crate futures; // 0.1.1
extern crate hyper; // 0.12

use std::net::SocketAddr;
use hyper::service::service_fn;
use hyper::{Body, Request, Response, Server};
use futures::prelude::*;

fn main() {
    let token = std::env::args().next().unwrap();
    run(&token, "127.0.0.1:8080");
}

fn run(bot_token: &str, listening_address: &str) {
    let addr: SocketAddr = listening_address.parse().unwrap();

    let server = Server::bind(&addr)
        .serve(move || service_fn(|x| echo(x, bot_token)));
}

fn echo(
    req: Request<Body>,
    bot_token: &str
) -> impl Future<Item = Response<Body>, Error = hyper::Error> + Send {
    futures::future::ok(Response::new(Body::empty()))
}

The problem here is that hyper require callback to be static:

error[E0621]: explicit lifetime required in the type of `bot_token`
  --> src\main.rs:18:10
   |
14 | fn run(bot_token: &str, listening_address: &str) {
   |        --------- consider changing the type of `bot_token` to `&'static str`
...
18 |         .serve(move || service_fn(|x| echo(x, bot_token)))
   |          ^^^^^ lifetime `'static` required

error[E0621]: explicit lifetime required in the type of `bot_token`
  --> src\main.rs:19:10
   |
14 | fn run(bot_token: &str, listening_address: &str) {
   |        --------- consider changing the type of `bot_token` to `&'static str`
...
19 |         .map_err(|e| eprintln!("server error: {}", e));
   |          ^^^^^^^ lifetime `'static` required

If I follow this advice and change telegram_client lifetime to static I get an error that closure may outlive run function.

How should I avoid it? I found that I may make it working in following manner:

fn run(bot_token: &str, listening_address: &str) {
    let addr: SocketAddr = listening_address.parse().unwrap();

    let bot_token = Arc::new(bot_token.to_string());
    let server = Server::bind(&addr)
        .serve(move || {
            let bot_token = bot_token.clone();
            service_fn(move |x| echo(x, bot_token.clone()))
        });
}

fn echo(
    req: Request<Body>,
    bot_token: Arc<String>
) -> impl Future<Item = Response<Body>, Error = hyper::Error> + Send {
    futures::future::ok(Response::new(Body::empty()))
}

But it looks weird, as well as reference counting for a situation when we know that we won't drop the reference until program exit.

Alex Zhukovskiy
  • 9,565
  • 11
  • 75
  • 151
  • 1
    I believe your question is answered by the answers of [How do I create a global, mutable singleton?](https://stackoverflow.com/q/27791532/155423) and [How can you make a safe static singleton in Rust?](https://stackoverflow.com/q/27221504/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jun 23 '18 at 13:30
  • 1
    @Shepmaster I tried to remove all unnecessary things, I hope I didn't throw the baby with the bathwater. – Alex Zhukovskiy Jun 23 '18 at 14:25
  • 2
    Thank you for minimizing your code. I took another look and I now think this question is a duplicate of [How do I call a function that requires a 'static lifetime with a variable created in main?](https://stackoverflow.com/q/50740632/3650362) In your case, since `lazy_static` won't work, and you don't want to use `Arc` because the value will never be dropped until program termination, `Box::leak` (mentioned in Shepmaster's answer) is what you're looking for. – trent Jun 23 '18 at 15:49
  • 1
    (Although I suggest using `Arc` anyway; a little reference counting overhead in exchange for knowing the contents will be dropped when no longer needed is usually a good trade.) – trent Jun 23 '18 at 15:55
  • @trentcl I tried to use `Box::leak` but it didn't work to me (see question without edit to see how exactly it was implemented). Although I'm going to follow your advice, I'd appreciate if you write an example with `Box::leak`, especially when there is not answer to mark while I'd like to have one (to keep this question searchable). – Alex Zhukovskiy Jun 23 '18 at 17:00
  • Questions that are marked as duplicates are not deleted, so it will remain searchable in any case. But I would have written something a lot like [this](https://github.com/Pzixel/boyan_detector_bot/blob/ed0160070bfabe42a2417383399911ff8057586b/src/main.rs). What was the error message you got with that version? – trent Jun 23 '18 at 19:20
  • @trentcl well, this is why I see that it could be an interesting answer: it doesn't compile. Here is an error: https://pastebin.com/VbeFUqW7 . If I explicitely do `move` then [this error](https://pastebin.com/HnRj4fDr) occurs instead. – Alex Zhukovskiy Jun 23 '18 at 19:32
  • Hm. Okay, I don't know why the `move` version doesn't work; I would have expected it to. So I can't answer it. But perhaps if you edit your question to focus on this particular problem -- why it doesn't work when you're using an actual `'static` reference -- you will get some real answers. – trent Jun 23 '18 at 20:50

0 Answers0