6 ms·
Given the number of Rust developers reading this, it's probably going to be very helpful for them if you can describe what you actually got hung up on.
by gcp 10y ago
Given the number of Rust developers reading this, it's probably going to be very helpful for them if you can describe what you actually got hung up on.
- ainar-g 10y agoThis was a few months ago, so I had to dig up some code: https://is.gd/kQJ7nv 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.
- steveklabnik 10y agoThis 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 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 https://github.com/rust-lang-nursery/thanks/tree/master/http is the implementation, https://github.com/rust-lang-nursery/thanks/blob/master/src/main.rs#L39-L63 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.
- ainar-g 10y agoI'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.
- steveklabnik 10y ago> 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#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.
- yarper 10y agohttps://github.com/ninjabear/nickel-bootstrap https://github.com/ninjabear/nickel-bootstrap You might be interested in this
- rspeer 10y agoHere's a wart. Why is reading lines from a file so hard? It's one of the first things people are going to need to do in a programming language. On top of handling errors (which I understand is necessary, and which the ? operator makes easier), it requires importing BufReader and BufRead, and wrapping a reference to a file handle in BufReader. Nobody is going to know how to do this unless they come across it in Rust By Example or on Stack Overflow. Shouldn't a standard library be able to abstract over fiddly details like this? Why is it my job to tell it how to buffer? I say this as someone who is enthusiastic about Rust, but still learning.
- douche 10y agoThat's a good point. It's slightly reminiscent of Haskell, where you have to start trying to understand the IO monad and do notation to do the most trivial real-world examples. In other languages, you might do File.ReadAllLines("foo.txt"), and bam, you're done.
- dripton 10y agoUnless foo.txt is too big, in which case, bam, out of memory.
- rspeer 10y agoIterators exist.
- int_19h 10y agoIn C# (from which the original example is), these days - and for like 6 years now - what you do is File.ReadLines, and you get a lazy enumerator.
- sametmax 10y agoNo, Python, ruby and such have a common interface for all lazy iterations. In Python you can just loop on anything declaring the __iter__ method, and it will lazily yield results little by little. IO related objects implement it plus an additional layer of interface so that you can do: with open('file', [mode, encoding]) as f: To get an auto closing file handle and then choose: - for `line in f` to lazy read it line by line. This calls __iter__. - `f.read([byte_count])` to read it all or some bunch of bytes. `f.seek(index)` to move around, etc. - `f.readlines()` to get a list of all lines in memory. - `f.close()` if you wish to close the file manually instead of letting the `with` keyword doing it work you. This interface works for most IO, including files, sockets, in memory buffers, etc. So you can choose an automatic lazy loading, a manual loading, load everything in memory, etc. And still have a lot of control. I think rust should get some traits to expose such a common high level interface on top of the current way it deals with files, to ease simple operations. Just make sure the documentation states what you can do to go lower level. There is a similar trend with many basic topics trying to do that as 3rd party libs too. click makes creating cmd UI very easy on top of argparse which is lower level. pendulum is higher level than datetime. requests higher than urllib. etc. Those all make doing those very common operation super easy. Now rust is not meant to be Python/Ruby/whatever, being very low level, and checking safety at compile time implies very different requirements. But those communities have some good concepts on API ergonomics and it would be a shame to not steal ideas from them.
- rspeer 10y agoAnother wart (in a separate post from my other wart so that replies are coherent): I understand why &str and String are different, but why do they act like they've never heard of each other? Why do they implement such different sets of methods? Why can't they be compared for equality, so I don't always have to type "literal".to_string()? Haskell has problems with too many string types as well (worse than Rust, because the type of their default string literals is best avoided entirely), but they fix much of the problem with the OverloadedStrings extension, which uses the type checker as something that helps you coerce string literals, instead of arguing with you.
- steveklabnik 10y ago> Why do they implement such different sets of methods? String gets all relevant str methods from Deref; it has some additional methods, but it should largely be shared. > Why can't they be compared for equality, Hm? They both compare just fine with ==.
- rspeer 10y agoI mean, if I have a method foo() that returns a String, as many methods do, why can't I check if foo() == "bar"? Why do I have to check foo() == "bar".to_string()?
- dbaupp 10y agoString == &str works. Maybe you were encountering some other problem.
- rspeer 10y agoOh, I guess the case of this I encountered most recently was actually Option<String> == Option<&str>. I get why that's different, but it would be great if the type system could figure that out, so that the literal Some("foo") could be an Option<String> if necessary. Maybe I'm still being spoiled by Haskell's OverloadedStrings.