3 ms·
I have no experience with Rust, but have been using Go professionally for ~5 years now. For a lot of the flak that Go gets (and praise that Rust gets), the Go s
by ar_lan 3y ago
I have no experience with Rust, but have been using Go professionally for ~5 years now. For a lot of the flak that Go gets (and praise that Rust gets), the Go standard library (and supporting ecosystem) indeed is fantastic for anything relating to a web server.
When I analyzed Rust around the same time, I noted the Rust standard library [1] did not have HTTP support, and it wasn't a first class consideration. I think Hyper [2] was around, but I've never analyzed it deeply (though based on GitHub stars it seems to be popular). Protobuf [3] is also extremely easy to work with in Go.
Given the differences in standard library and applications I see created in both ecosystems, your analysis seems right, though you can probably develop network(ed) applications in both fairly well at this point.
[0]: https://pkg.go.dev/std https://pkg.go.dev/std
[1]: https://doc.rust-lang.org/std/ https://doc.rust-lang.org/std/
[2]: https://github.com/hyperium/hyper/ https://github.com/hyperium/hyper/
[3]: https://github.com/golang/protobuf https://github.com/golang/protobuf
- juancampa 3y agoThese days Axum is the most common way of building an HTTP server. It sits atop Hyper and it’s very composable thanks to Tower. It supports Websockets out of the box too.
- dgb23 3y agoNot more than a couple of months ago people would recommend actix. There is a lot of enthusiasm and excitement behind the language and the ecosystem reflects that, for better or worse.
- earthling8118 3y agoPeople will still recommend actix. That doesn't mean that axum wouldn't be recommended either. It was there a couple of months ago too and doing extremely well.
- throwaway894345 3y agoYeah, and I genuinely want to like Rust and I pick it up a few times every year (and have done for the last decade), but each time I get burned by trying to do something that would be trivial (and safe!) in Go or C. Most recently, I'm trying to build a non-allocating, minimally copying `Lines` iterator which reads from an internal `Reader` into an internal buffer and then yields slices of the internal buffer on each call to `next` (each slice represents a single line, and it's an error if a line exceeds the capacity of the internal buffer); however, as far as I can tell, this is unworkable without some unsafety because the signature is `fn next(self: &mut Lines<'a>) -> Result<&'a [u8]>` which doesn't work because Rust thinks the mutable reference to self must outlive 'a, and explicitly setting the mutable self reference to 'a violates the trait. If I forego the trait and just make a thing with a `next()` method, then I can't use it in a loop without triggering some multiple mutable borrows error (each loop iteration constitutes a mutable borrow and for some reason these borrows are considered to be concurrent). The only thing I can think to do is have a `scan()` method that finds the next newline and notes its location inside the `Lines` struct and a separate `line()` method that actually fetches the resulting slice from the buffer. I don't run into this in C or Go, and for all of the difficulty of battling the borrow checker, I'm not getting any extra safety (in this case).
- masklinn 3y agoWhat you're talking about is the canonical example for generic associated types, which were stabilised late 2022: https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#generic-associated-types-gats https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#gener...
- throwaway894345 3y agoAh, good to know. Thanks!
- burntsushi 3y agoAlternatively, use a closure: https://docs.rs/bstr/latest/bstr/io/trait.BufReadExt.html#method.for_byte_line https://docs.rs/bstr/latest/bstr/io/trait.BufReadExt.html#me... There are downsides to this approach because it uses internal iteration while most things in Rust use external iteration. But shit happens. Go doesn't even have a first class concept of iterators as an abstraction (yet), and its standard library contains patterns for both internal (sync.Map) and external (bufio.Scanner) iteration. > The only thing I can think to do is have a `scan()` method that finds the next newline and notes its location inside the `Lines` struct and a separate `line()` method that actually fetches the resulting slice from the buffer. Yup that works too. That's basically the design used by the `streaming-iterator` crate: https://docs.rs/streaming-iterator/latest/streaming_iterator/trait.StreamingIterator.html https://docs.rs/streaming-iterator/latest/streaming_iterator... > I don't run into this in C or Go Of course you don't. Neither C or Go even have abstractions called "iteration" at all. They have patterns for them. And Go lets you iterate over a fixed set of built-in types. (Currently. Maybe it's changing: https://research.swtch.com/coro https://research.swtch.com/coro) Besides, Go has a garbage collector. You should expect all sorts of patterns involving memory/copying to change when you move from a language with a GC to one without.