Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This was a few months ago, so I had to dig up some code: https://is.gd/kQJ7nv

Basically, I tried to create a very basic HTTP server the way I would in Go, but I kept getting all sorts of lifetime errors and kept adding stuff go get away from them. So the code has issues, lots of them. Arc<Mutex<>> was recommended by a guy at the job, I don't even know why I need an Arc here, for example.

The compiler says

    consider using an explicit lifetime parameter as shown: fn handle<'a,
    'b>(&self, req: server::Request<'a, 'b>,
    mut res: server::Response<'a>)
But when I do that I get

    error: `user_index_handler` does not live long enough
And there I'm stuck. The user_index_handler is declared and initialised literally one line above. I don't understand why Rust thinks it can just delete it immediately after I've created it.


This issue is a little bit too much in the weeds (and I'm not sure what version of Hyper you were using, it's had some big releases lately) but if you're curious, I recently implemented a basic HTTP service with a router. I still have some cleaning up to do, but https://github.com/rust-lang-nursery/thanks is the repo, and the code similar to yours is https://github.com/rust-lang-nursery/thanks/tree/master/http is the implementation, https://github.com/rust-lang-nursery/thanks/blob/master/src/... is the core of using it.

I _think_ the issue here is that Request and Response both have lifetimes. The compiler suggestion you're seeing was recently removed for having too high of a false positive rate, which I believe is what happened here. By doing that, you say that the handler must live as long as the Request and Response, which is not true, since it's created inside the functions but they're passed as arguments.


I've actually got that error with 1.15 as well. Or by "recently" you meant "on the nightly"? I updated hyper to 0.10.4, but the issue is still there.

I will check your example app out (thanks for that!) but the problem in my code still remains and I hate the fact that I can't understand what's going on. That might be my biggest issue with Rust compared to Go. Something doesn't match and I don't know how to find the issue without going to IRC or /r/rust; with Go I've never had an issue that wasn't resolved by carefully reading the language/library docs or StackOverflow.


> Or by "recently" you meant "on the nightly"?

Yeah, it was removed literally last week, so it hasn't made it into a release yet.

Without knowing what version of postgres you're using, I can't _totally_ get this to compile, it complains that SslMode isn't there. But, I did fix your issue:

  fn handle<'a, 'b>(&self, req: server::Request<'a, 'b>, mut res: server::Response<'a>)
This compiles for me.

The issue here is lifetime elision. http://rust-lang.github.io/book/ch10-03-lifetime-syntax.html...

Specifically, rule 3:

> If there are multiple input lifetime parameters, but one of them is &self or &mut self, then the lifetime of self is the lifetime assigned to all output lifetime parameters.

So here, Request and Response both have lifetime parameters. This means that your original signature is the same as

  fn handle<'a>(&'a self, req: server::Request<'a, 'a>, mut res: server::Response<'a>)
Which says "when I call handle, I borrow myself for as long as request and response are borrowed." That won't work; user_index_handler only lives for the duration of the call.

The fixed signature says

  fn handle<'a, 'b>(&self, req: server::Request<'a, 'b>, mut res: server::Response<'a>)
"When I call handle, the request and response share one lifetime, and request also has another lifetime."

You're no longer connecting &self to the request and response, and so things are just fine.

Honestly, this isn't the simplest signature; it's not surprising that you got stuck. This is also what people mean when they say "I fought with the borrow checker for a while, but then got over it", as it took me less time to fix this error than to write out this comment explaining how to! But until you've got that intuition and understanding, it can feel like hitting a brick wall.


Wow, thanks for the reply. I copied the signature directly from your post and... it didn't work. I still got `user_index_handler` does not live long enough. But! If I replace

    impl server::Handler for UserIndexHandler
with

    impl UserIndexHandler
it does compile. Removing the trait impl was another thing recommended by the Arc guy at work, he didn't know how or why it worked. Here is the code that doesn't compile with updated Postgres: https://is.gd/fjYDIG.

Which brings me to a question, how does implementing a trait prevent this code from compiling? Sorry for comparing apples to oranges again, but in Go implementing an interface is an invisible operation, that doesn't affect compilation. What's different with Rust?


I am about to go into two hours of meetings so this will have to be quick.

The issue is, because this is a trait, you must conform to its signature. Which is here: https://hyper.rs/hyper/v0.10.0/hyper/server/trait.Handler.ht... and specifically https://hyper.rs/hyper/v0.10.0/hyper/server/trait.Handler.ht...

So yeah, my idea won't work, because those types conflict.

> Removing the trait impl was another thing recommended by the Arc guy at work, he didn't know how or why it worked.

I'm surprised it works on first glance, as I was assuming that you were implementing the trait for a reason, not just because. If you don't need the trait, then yeah, it's much easier.

> What's different with Rust?

See my StackExchange link elsewhere in the thread for a summary.

I'll maybe poke at this after my meetings, or maybe tomorrow. We'll see how amped I am for coding after all that ;)


Okay, thank you again for your time!


Ah! I understand now.

Handlers aren't meant to be nested like this. That is, it's always going to break this way, because the handler needs to live as long as the request and response, so creating a sub-handler is not ever going to live long enough.

So yes, the solution is to not implement Handler for your UserIndexHandler; then you can just call it.

I bet there's something larger you could do as well, but I don't have enough experience with this interface to give good advice. Hyper's undergoing a huge docs drive for 0.11; I'm sure that'll help.


Yeah, I figured that out as well, but thank you for finding the time to analyse the code and write an answer. I appreciate it and may be on my fourth attempt at actually learning Rust :)


No problem. :)


Why not use Iron or Nickel?


They don't have support for async IO yet; this is using hyper master.


getting a bit off topic now - but I'm curious as to if async/io has improved performance by much? Do you have any benchmark comparisons?


http://aturon.github.io/blog/2016/08/11/futures/ is old but has some benchmarks in it; a lot has changed since then, but the blazing speed is still there.

I haven't benchmarked this particular application because I haven't had the time, and it's never going to see particularly higher load.


https://github.com/ninjabear/nickel-bootstrap

You might be interested in this


Why would someone trying to learn Rust be interested in a web framework? I think they ought to learn how Rust works first, or they'll just be more confused.


Different strokes for different folks




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: