14 ms·
A half-hour to learn Rust
- qgadrian 7y agoLoved the approach, no time wasting and you can dig on things are not clear for you.
- 131hn 7y agoOnly, it’s more one hour and a half rather than half an hour. Excellent quality stuff nonetheless
- csomar 7y agoIt's only an half an hour if you are familiar with these concepts (generics, traits, pattern matching, error propagation, etc...). Some concepts are exclusive to Rust (lifetimes/ownership), so I doubt you can get it in 30 minutes if you have never written code in Rust before.
- cormacrelf 7y agoI’ve seen this guy’s posts a few times lately, he needs to learn to edit things down. What he’s saying is good, but it is extremely digressive, and the digressions never seem to return to the original point. I’m not the audience for this so I don’t have that much time to spare reading it, but I can’t imagine that style working well for an introduction to a language.
- fasterthanlime 7y agoI respectfully disagree but - can't make everybody happy. There's plenty of introductory articles to Rust in the style you desire :) edit: To expand a little bit, the digressions aren't just about me "getting distracted" while writing - they're very much on purpose. I always try and write pieces that expand in many different directions, because there's so much to discover, always. Some folks come to an article wondering why Rust has two string types and end up spending an hour on Wikipedia reading about legacy code pages - and I think that's great. My way of getting people interested in something is never a top-down, present-the-bare-minimum way, it's always about showing how what we're discussing is connected to a lot of other things, which are also fascinating and that you should check out if you want!
- cormacrelf 7y agoI think I'm talking more about your Mr Golang piece, but now that I have your ear, I guess may as well. I am less concerned with the existence of digressions than the way they're introduced. When I say needs editing, I mean that because I cannot navigate the piece properly, it takes longer to understand what you're getting at if I want to, so it seems like it's too long. Editing down is only one solution to that. An example of this is when I was really confused reading about path extensions and non-UTF8 paths. I was promised by Cool Bear that you had a point to make using an example about a stat call, but you were no longer talking about stat, and yet you were still writing as if it was central to your stat discussion. So instead of expanding, I thought you just couldn't express what was wrong with the stat call. I nearly gave up waiting! And I was surprised that, in the end, you could (and put it quite well). Unfortunately, there are thousands of thinkpieces out there that never make the point they promise to, instead just dumping information at you and hoping it hits you like it hit them. So I am trained to close the tab when that is happening. It might help to state why you're going to digress before you do, with a promise to return, so that people who are hooked can be confident you'll eventually make your point (and may skip back and forth to digest your argument again without interruption). If nothing else, you are making a promise to yourself to structure things in a way that is friendly to the reader. Rather than making the piece less exploratory, adding signposting helps get the reader into the mindset you describe in the last sentence there. Otherwise, they are not sure whether to be interpreting what you're saying as a core argument or some side discussion. It hurts both the exploratory and the argumentative qualities of the writing if one is confused for the other. Without making it clear, the argument runs like my first para above: unnecessarily long-winded and questionably relevant, with no exploratory levity. With good signposting, you get to nail both. It's about two sentences' and two headings' difference, maybe a little shuffling around. Hope that helps, looking forward to your next one.
- fasterthanlime 7y agoThe Golang piece is definitely subpar, it was quickly thrown together in half a day, didn't expect it to be spread so widely haha. For other articles there's usually a few days of research, and 1.5 days of writing and editing, then a lot of touch-ups in the following weeks/months responding to feedback. Thanks for the more detailed criticism though - I agree with the general sentiment, and haven't solved the navigation problem yet!
- pgt 7y agoReminds me of Learn X in Y Minutes: https://learnxinyminutes.com/docs/rust/ https://learnxinyminutes.com/docs/rust/
- csomar 7y agoNumbers could also be differentiated in Rust. For example, to make sure your "16" is an i32 you could write > let x: i32 = 16i32; Otherwise, it's a very comprehensive article. The only missing parts are the async/await keywords and the sync primitives (like Mutexes/RwLocks).
- JoshTriplett 7y agoYou don't need both of those "i32"s. Rust has type inference, so you can just write either `let x = 16i32` or `let x: i32 = 16`.
- csomar 7y agoI use it mostly if I'm passing arguments to another function. It serves as some sort of code documentation. > my_function( 44i32 ); That makes it clear from the code that function accepts an i32 and not any number.
- inferiorhuman 7y agoThe type signature of the function will also enforce that. You can also use generics to allow you to accept a wider variety of numbers, e.g.: fn takes_a_float_like_number<T>(number: T) where T: Into<f64> { // Number will now be a 64-bit IEEE floating point object // for this scope let number = number.into(); } This will only compile if your type is small enough to fit into an f64. So takes_a_float_like_number(500_u32) will compile but takes_a_float_like_number(500_i64) will not. The error message will be a wee bit obtuse as it will be something like "trait Into<f64> not implemented for i64".
- estebank 7y agoHow would you improve that error?
- unlinked_dll 7y ago
- Karupan 7y agoI found this extremely helpful. I’ve always been interested in Rust but never got around to it cause most of the source code I’ve read on GitHub was overwhelming. This is a nice walkthrough to get someone like me interested. Great work!
- jokoon 7y ago> let x: i32 = 42; I'm sorry but this notation will always make me scream. C is so much simple: int x = 42; not "let", no colon, and no ambiguous "i32 = 42"
- bschwindHN 7y agoHow about `let x = 42` and let type inference do the work? I used to do a lot of C-style variable declarations in other languages but I'm warmed up to Rust's really fast because most of the time I don't need to explicitly name the type.
- jokoon 7y ago"let" should be removed, and it doesn't change that the type should be placed before, not after with a colon.
- gameswithgo 7y agothen you have to introduce new keywords in other places to remove ambiguity.
- chrismorgan 7y agoWhether a type should come before or after the name is a fairly subjective matter. I believe that after is generally superior, especially when the type is optional. But there’s a very practical reason for requiring the `let` token: it makes parsing very much easier. With `let`, you can keep a LL(1) grammar, because seeing `let` tells you to next parse a pattern, then if there’s a colon a type after that. But if you don’t put something in there, you get a genuinely intractable problem once type grammar is not trivial: sure, `int foo;` is simple and obvious, but what about `A<B, C> d;`? should that be parsed as an expression (respaced, `A < B, C > d;`). Some languages have not resolved this style of parsing ambiguity at all, and figure it out at runtime, based on what else they find (Perl is infamous for this). I think others only kind-of resolve it, by looking at what symbols are present at compile time, to decide what was meant. Others just declare that such ambiguities are parsed one way, and you can rewrite your code (e.g. add parentheses) if you want to mean the other. Still others have resolved it otherwise, by other more subtle syntactic means, so that even if you need arbitrary look-ahead while parsing, there’s not quite any overlap between the two syntaxes (e.g. don’t support commas in this way as a kind of alternative to semicolon within expressions; or use proper matched delimiters like [] or () for generics). Rust chooses to make parsing simple, which benefits humans as well as machines, reducing cognitive requirements in reading code. Furthermore, in Rust what follows `let` is not an identifier or identifier list, but rather a pattern. Imagine the following contrived example: let x = [[0]]; type x = [u32; 1]; let a = 0; let [a]: x = [1]; That falls over completely if you put the type first: `x [a] = [1];`—does that define a new binding a with value 1, or does it set x[0] to [1]? And finally, as I mentioned, the type is optional, and not commonly required, so you end up with something like C++’s `auto` keyword, which is basically `let` but spelled worse (and with worse semantics). The end result is that for Rust specifically, what you desire is quite unsuitable, and what it has works very well—and that its reasons for doing things that way are well worth while considering.
- owaislone 7y agoThis is great write up. I wish every language had this on their official page. I'd personally love one for C++.
- kzrdude 7y agoUnderscore is not exactly "throw away" but rather it is exactly "don't bind to variable". The difference becomes evident with the statement: let _ = x; This is a no-op and the value remains owned by the variable x, and is not thrown away.
- nightcracker 7y agoUnderscore can also be the equivalent of a wildcard in pattern matching.
- saghm 7y agoI think that's the same thing as in let bindings; just like you can bind to a name in the wild card case, you can also choose not to bind to it. The main difference is that not binding in the wild card case is more common than in `let` bindings.
- fasterthanlime 7y agoI debated which terminology to use and thought "throwing away" was more intuitive, especially if you've never heard of "binding" before. It has its limits though - in your example I'd say you're throwing away the result of evaluating "x", just as if you did: x;
- kzrdude 7y agoI don't agree, because we can try the two following programs, and one of them does not compile. It compiles with underscore. 1: let x = String::new(); let _ = x; println!("{}", x); 2: let x = String::new(); x; println!("{}", x); // ERROR: Use of moved value x. And this is why I said that let _ = x; is a no-op. :)
- Tehnix 7y agoI think no-op is a bit misleading, and throwing away is more precise, since Rust has strict evaluation. let _ = timeConsumingFunction(); Still needs to spend time performing timeConsumingFunction(). It might not move, but it still did the work and produced a result, you are just not using it (and hence not need to move it). If you you had lazy evaluation I would agree with your argument for the no-op terminology.
- jariel 7y agoEvery young language must have tutorials like this. Start with the utter basics but move quickly through the common issues. More than anything, these kinds of tutorials make it possible to at least start grasping the rest of the documentation. I find with so many funky languages, the little examples aren't so hard, but there's too much 'unknown' syntax in the way to make sense of it. These are essential.
- fenk85 7y agoVery nice! first impressions is that it is very similar to Kotlin which i love working in, seems modern languages are converging on common set of niceties
- unixsheikh 7y agoWhat a nice approach to presenting the language in a clear cut way. We should have this for every language out there.
- abledon 7y agoive been perusing a bit of rust code for the past 2 years, reading an article here and there....always heard it was a complex and low level , next generation C language. comparing it to go etc... but never wanted to learn it... This article is _so_ simple in its delivery. It really got excited in the 'beauty' presented by each simple chunk.
- jononor 7y agoNice. What is dont understand is why is the second Vec2 used in this example? It introduces x and y, which are of type float right, not Vec2? let v = Vec2 { x: 3.0, y: 6.0 }; let Vec2 { x, y } = v; // `x` is now 3.0, `y` is now `6.0`
- wizzwizz4 7y agoBecause you're ---unpacking--- destructuring a Vec2. The most common form of this idiom I've seen is: if let Some(x) = foo() { println!("{:?}", x); } where fn foo() -> Option<_>, i.e. foo returns either Some(_) or None. (if let is used to account for the possibility of None; it's technically different syntax to let, but very similar.) Here, x isn't a Some (a variant of Option). It is, however, representing a value inside a Some, which we want to get out. Likewise with your example; we want to destructure from a Vec2, so we specify a Vec2 (with identifiers instead of data) on the left hand side and the data on the right hand side, and it takes the data out and binds it to the identifiers.
- esjeon 7y agoNothing related to the tutorial itself, but I've seen many Rust basic tutorials recently, and this sorta remind me of Haskell - especially its Monad. The Haskell community once was flooded with Monad tutorials[1]. People kept trying to put meanings on this mathematical construct, and had come up with tons of different ways to describe it. The problem is, this simple thing can fit into so many different places, so people couldn't possibly run out of new ideas. This oversaturation only confused newcomers even more, so the community concluded not to write any more Monad tutorials. While individual tutorials enrich the community in general, it's more crucial to have a few good documentation that kill the need for more tutorials (e.g. MDN + W3School), so that efforts can be redirected into more productive things. Rustonomicon is one good documentation, but it always falls few steps short in practice. That's probably why more tutorials are being written, and why they get upvoted well in both HN and Reddit. [1]: https://wiki.haskell.org/Monad_tutorials_timeline https://wiki.haskell.org/Monad_tutorials_timeline
- whatshisface 7y agoThe dust is settled and the fight is over. Which monad tutorial won "best monad tutorial?"
- jerf 7y agoNone of them. The concept is fundamentally flawed. It's as if everything you ever read about C was all about bitwise manipulation operations, on and on and on about bitwise manipulation, to the point not-C programmers think the language is primarily about bitwise manipulation and people start porting bizarre misunderstandings of bitwise manipulation into other languages and claiming they're just like C now, when it's just a part of the language that you'll pick up over time. Not a perfect metaphor but close enough.
- tiborsaas 7y agoSo how far can I go in Haskell without "getting" monads? I C that would be pretty far without bitwise operators.
- ryuukk_ 7y agoso that is why he complained about go how much Mozilla paid for this article?
- talkingtab 7y agoThis is the most useful introduction to a language I have ever read. Often language introductions produce a "Wall of Complexity" and I failed in my last two attempts learning Rust failed because of that. This is just great. Be warned, the "half hour" part is probably a bit like "99 cents" as a price tag. I've already spent more than that, but it is time well spent. Thanks for writing this!
- galfarragem 7y agoYou might like this: https://learnxinyminutes.com https://learnxinyminutes.com
- spectramax 7y agoI use this website as the most effective cheatsheet ever. Forget about PDFs and all these things people put together. Pretty much every programming language is on LearnXinYMinutes and it is like a standardized cheatsheet across all languages. Brilliant, so brilliant!
- nobleach 7y agoI also like Derek Banas videos (https://www.youtube.com/channel/UCwRXb5dUK4cvsHbx-rGzSgw https://www.youtube.com/channel/UCwRXb5dUK4cvsHbx-rGzSgw) for this same quality. He doesn't do many "deep dives" into the languages, but he does a fantastic job getting your feet wet with very common tasks... much like these learnxinyminutes pages do.
- da-x 7y agoI wish this could be extended to "Learn X in Y minutes coming from already knowing Z". However this (X,Z) matrix is hard to maintain...
- chris_st 7y agoI agree, this is a great page. I failed to make it through the Rust book in (I think) 2017, and kind of hated it; I made it through easily in 2019 and enjoyed it... the book has improved that much. Oh, and the compiler error messages are better, too, which helps enormously.
- sgt 7y agoSerious question; why aren't we all using Rust?
- zimpenfish 7y agoI think for a lot of use cases, the safety and security and whatnots you get from Rust just aren't required and people already have a large time investment in Python/Go/Java/etc. Certainly I can do pretty much everything I need to with C/Python/Go because I accept the tradeoffs and know enough to work around the safety/security issues. (But Rust is on my list of things to get around to in 2020.)
- michaelangerman 7y agoI am really happy I found this blog post. If you like this one you should check out some of his other posts. He has some amazingly insightful other posts on Rust including some very in depth topics. Also, a great comparison of Rust and Go. This is also why I love Hacker News. I would have never found these posts if this one had not made it to page one.
- donmcronald 7y agoI want off Mr. Golang's Wild Ride [1] is a great read. The part about how different OS file permissions are handled in Go vs Rust is great. Even though I don't know Rust, I thought the Rust approach looked easiest since it's accurately represents the underlying systems. It was really surprising to see that Go's motivation in glossing over the complexity is to keep things simple. Is a half working implementation really simpler? 1. https://fasterthanli.me/blog/2020/i-want-off-mr-golangs-wild-ride/ https://fasterthanli.me/blog/2020/i-want-off-mr-golangs-wild...
- 127 7y agoFor a clickbaity title, it's surprisingly useful. Of course, the time to read it might take half an hour, but the time to really absorb it might take two weeks.
- harel 7y agoI wish all languages had this kind of page as a requirement of the language manual. Author, I will hold your beer...
- plutonorm 7y agoNext up: Learn mandarin in 0.1^99999999999999999999 seconds.
- svnpenn 7y agoHas anyone struggled with the lack of HashMap literal? https://github.com/rust-lang/rfcs/issues/542 https://github.com/rust-lang/rfcs/issues/542 I just cant bring myself to doing something like this: let m1: HashMap<&str, i32> = [("Sun", 10), ("Mon", 11)]. iter(). cloned(). collect(); https://doc.rust-lang.org/std/collections/struct.HashMap.html https://doc.rust-lang.org/std/collections/struct.HashMap.htm...
- dmit 7y agoWould a macro work ok for you, like the inbuilt vec! one? There's a crate for that named maplit: https://docs.rs/maplit https://docs.rs/maplit let map = hashmap!{ "a" => 1, "b" => 2, };
- gameswithgo 7y agoone of the fun things about Rust, is any time you think "man I wish there was some syntax to do this thing in Rust" you can make a macro to make it reality, usually one already exists.
- j1elo 7y agoI assume it must be a common finding. I have too wanted to initialize a map value with a literal, only to find that one needs to juggle around their absence. Very weird thing to miss in such a great language, really. I guess that the syntax proposal would get too complicated with all the different possibilities (like what happens if you want to store one ref, now you need to add lifetimes and such), but overall for the novice it just looks like a strange thing to not have.
- gameswithgo 7y agoyou can so easily make a macro in rust to do exactly what you want, that it doesn't likely make sense to include it as part of the language. though perhaps the macro should be in the core libs.
- 7y ago
- j1elo 7y agoClose to the beginning there is a phrase you'll want to review: > If we we really we wanted to annotate the type of pair, we would write Ok understood, we're us and we're all together in reading this! :-)
- pansa2 7y agoTypo: “If we we really we wanted”
- krebs_liebhaber 7y agoThe way I like to think about the expression / statement divide in Rust is that everything is an expression, and the semicolon is an operator akin to `ignore` in F#; it takes any operands, disposes of them, and returns the unit type `()`. Rust in general is just such a pleasant language. It can be a bit tedious to work with sometimes, but that's usually because the problem in question is tedious in and of itself, and you didn't even notice all of the little screw-ups that could occur until you saw how Rust dealt with it.
- dmitriid 7y agoThis is very good but... Description of traits suddenly dumps references, mutable references, reference bindings, dereferencing with zero explanation: --- start quote --- Trait methods can also take self by reference or mutable reference: impl std::clone::Clone for Number { fn clone(&self) -> Self { Self { ..*self } } } --- end quote --- What? What does this even mean? What is <asterisk>self, and why? Too many questions, not nearly enough answers.
- dilap 7y agoIf you have a struct of type T and an instance of that struct t, you can create a new instance using the syntax T { ..t } which means "a new T with all the fields set to their values in t". Inside the trait "Self" is an alias for "Number". "&self" is shorthand for "self: &Number", i.e., a reference to Number. To dereference a reference, prefix with * So: self has type "&Number" and *self has type "Number". Thus, Self { ..*self } is creating a new instance of Number with its each set to the same value as self. Disclaimer! everything I know about rust I learned 2 days ago from this blog post, so I might be wrong :-)
- clarry 7y agoI want books written like this. I've had too many books where I die of boredom over and over again in the first 150 pages and then I never read them again. It's like there's some rule saying books must be super wordy.
- TheRealPomax 7y agoThat rule is usually called the publication contract, and it usually literally says how big the work needs to be, even if you can say it better in fewer words/pages/chapters/etc.
- kanakka 7y agoTIL. This seems to be waste of paper/time for consumers. What is the incentive for publishers by preferring wordy version than terse one? Is it because they afraid of being perceived as not worthy enough to be a book?
- dilap 7y agoHoldover from another era. Pre-internet, we had more time to spend w/ books, and it was harder to gain context to make things make sense -- a little hand-holding and digression was more appropriate then.
- zimbatm 7y agoWhat does `type Output = Self;` for the `std::ops::Neg` trait mean? It wasn't explained on the page.
- Lev1a 7y agoIIRC that's called "associated type" and is mostly used for shortening the function declaration inside the trait through using e.g. "Self::Output". E.g. the definition of the real std::ops::Neg trait: https://doc.rust-lang.org/std/ops/trait.Neg.html https://doc.rust-lang.org/std/ops/trait.Neg.html
- steveklabnik 7y agoIt’s not about shortening things, it’s actually about semantics! Choosing to make something have a type parameter vs an associated type depends on what you’re trying to accomplish.
- dmitshur 7y agoI really enjoyed this, and it also inspired me to try a quick experiment: what would the same blog post look like for Go? I tried it and wrote https://dmitri.shuralyov.com/blog/27 https://dmitri.shuralyov.com/blog/27. It was a fun exercise to go through.
- vajrabum 7y agoI did enjoy the article. It was quite clear but it made me wish for a bit more. Unlike the Rust article I didn't see any thing that suggested how golang might be special. I did see your suggestions for further reading though. I'll check them out.
- dmitshur 7y agoThanks for feedback. I think the “special” part for me was that there were large sections of the Rust blog that I could skip having to explain, because they aren’t a part of the Go language. To me, Go is a language that’s much easier to learn and be productive with. Maybe I should make it more clear what I skipped.
- bogomipz 7y agoThanks for sharing. I enjoyed this. Could you elaborate on your closure example though? This was the only one I didn't understand. The explanation is a bit terse = "Closures are just variables with a function type with some captured context." Are these anonymous functions? What is calling the anonymous function if so in main? Cheers.
- dmitshur 7y agoThanks for feedback. I’ll try to clarify that section.
- dilap 7y agoThis is fantastic! Using it, I was finally able to write my favorite toy-problem in Rust (scoring a boggle board). Rust solution came out 25% faster than my (I thought) highly-optimized C++ solution, wow...
- 5Qn8mNbc2FNCiVV 7y agoThis is so good. I would love this kind of "learning" for every language. It's definitely not beginner friendly but for anyone that already knows a language this is a super introduction and quick start, maybe even tipping point to start using the language. Only remark: If I had anchor tags at specific points creating a reference would be easy, this is referenceable material. Great job though, I am amazed at the quality of this. Hell yeah!
- signa11 7y agois there a poignant guide to rust ? something similar to ‘learn you some erlang for great good’ ?
- jquave 7y agoI've been writing Rust for about 2 years, I read this and learned all kinds of stuff I still did not know. Fantastic job on this! I am now a bit upset that everything isn't taught this well :o
- perlpimp 7y agothis is the style that let me get into python reading a python book by new riders within 3 days. i replace perl based module within a week of reading. this: teaching material should give immediate confidence to apply learned material and - refine it later. excellent write up
- webew 7y agoDoes anyone know of a similar tutorial for C, C++, Python, et al?