Hacker News new | past | comments | ask | show | jobs | submit login
Rust Language Cheat Sheet (cheats.rs)
444 points by ivank 19 days ago | hide | past | web | favorite | 63 comments



I love the design of this site. It is compact, dense and to the point. I think we need to port cheatsheets for most popular languages in this format. There is also Learn Y in X minutes[1] which I often refer to but a cheatsheet like this where everything is neatly organized would be a huge help. I jump between 3-4 languages everyday and it is a pain in the ass to Google syntax, frankly embarrassing that I have to.

[1] https://learnxinyminutes.com/


Yes, agreed. The site is great and it would be nice to have a similar design for other languages. The closest example that I frequently use is cppreference[1] for C and C++, languages that I use just infrequently enough to forget the basic syntax.

[1] https://en.cppreference.com/


Oh, my! I have spend countless hours on the web looking for (and successfully finding, of course) cheat sheets for all sorts of languages, but somehow I had never come across this site. This is extremely well done. Thank you,spectramax, for basically revolutionizing my life this morning! :)


Surprisingly, https://learnxinyminutes.com/docs/bash/ is the best resource out there to learn shell scripting. This page basically turned me from a novice who could only write two commands with | or && between them to a competent shell programmer. My shell scripts have functions, descriptive variables, error handling, good formatting, etc.


I find shellcheck to be really great to go to the step beyound. It find a lot of things that make most shell script brittle and teach you some best practice.

Add shfmt on top and you are good to go.


Great quick reference, but a wasted opportunity to call the site “cheate.rs”.


The explanation of lifetimes linked here is really great - I think this goes a little further than just a cheat sheet. Seems to be more like excellent Clif notes.


Lifetimes are about where I bowed out of Rust. I haven't worked with C++ before, or really ever thought about borrowing or lifetimes, so it never really clicked in my head. What's worse is the Rust community's desire to remind you to "Just read the book". Maybe this would be a worthwhile read to get back into it?


The Book by Steve Klabnik looks fantastic for newer programmers, but as an experienced programmer I did find it difficult to get into. On the other hand, the O’Reilly book by Jim Blandy and Jason Orendorff is just amazing for experienced programmers (and would be unsuitable for new programmers). It’s the best programming language book I’ve ever read. It’s great that both books exist, filling those two niches.


Author here. Thank you all for your comments, issues and pull requests. You are amazing!


Any plans on adding Box, Rc, RefCell, and the differences thereof? That's the thing that trips me up the most right now.


To give you a quick summary:

Box is (mostly) used in two specific circumstances: when you want to have ownership of something that lives longer than a single function, and to create heterogeneous lists of things (a "trait object").

Rc is used when you need multiple ownership of something, and you're not going to be sharing those things between threads.

RefCell is a type that moves the borrow checker to runtime; it's useful when you're trying to mutate something, and Rust's static checking can't tell that it's okay. If you mess it up, you'll get a panic. This often happens in combination with Rc, since Rc makes something have multiple owners.


If you had an equivalent Cheat Sheet for other programming languages (no programs or opinions), which language would look best?


Smalltalk. Or Forth.

This cheatsheet is syntactic, both have very little syntax. You can famously exercise all of Smalltalk's syntax on half a postcard: https://miro.medium.com/max/1000/1*Aa0AEoUgjZov8yrgdplsIg.pn...

(the example doesn't feature primitives calls, not because they don't fit — a primitive call would be <primitive: xxx> — but because their use case is extremely specific to implementing a system).


Scheme has to fall somewhere between Smalltalk and Forth for quantity of syntax too. To me, these are the prettiest languages.


I didn't mention lisps because I'm never sure how to classify "built-in" special forms: should they be considered normal names and thus omitted from a syntactic overview or should they be considered keywords and included?

On the one hand they usually have non-normal evaluation and custom mini-languages, on the other so do most macros otherwise you'd just use a function.

But yeah, these are the sort of languages I think of as "simple": small languages which reach "smallness" by giving access to a limited set of extremely powerful constructs.


> small languages which reach "smallness" by giving access to a limited set of extremely powerful constructs

That's one of the things I really loved when working in Smalltalk: the language gives you all of the building blocks necessary to build more or less then entire standard library, which makes it extremely simple to implement custom control structures for your application. That, and the fact that you're programming directly in your running application of course.


Yes, and I'm not sure the R*RS standards even specify which special forms are fundamental vs implemented by macros. However, Smalltalk has some keywords too. In any case, it could be a concise cheat sheet.


> However, Smalltalk has some keywords too.

Indeed but they're all on the postcard above (true, false, nil, super and self).

Smalltalk's closest thing to built-in special forms would be primitives but they have a generic "shape" and they're pretty much always used as implementation details for the "normal" messages which system users interact with.



brainfuck or another esoteric language.


Pretty solid list, only thing I saw missing was binary representation for literals("0b0000_1000") which is really handy when working with micros or other things that use a lot of flags or bits.


As a Rust noob, what's the rhyme or reason for semicolons?

I see the example:

   struct S {}
but here the semicolon is required:

   type T = S;
or you get weird errors. It's hard to predict when a semicolon is required at least for type declarations, is there an underlying principle?


Every language item ends either with blocks (when a nested structure is required) or `;` (when it's not). They do not mix; if an item uses a block you don't need `;`.

So `type` needs no more blocks and ends with `;`, while `struct S { ... }` doesn't need `;`. Completing an example, there is another form of `struct` that looks like `struct S(u32);` which do need `;` by the aforementioned logic.

(The same logic applies to statements. You may think of an apparent exception like `{ println!("42"); 54 }`, but here `54` is an expression and you can't put a non-expression statement like `let x = 42` there without a semicolon.)


They appear to be similar to the way most other languages like C and Java use semicolons, where a semicolon isn't required after a code block (generally denoted by squiggly brackets), but is required at the end of most (all?) other statements.


The most confusing thing ever is, of course, the fact that C struct/union and C++ class declarations do require a semicolon after the closing curly bracket. This is because type declarations are permitted to occur inline in certain contexts, notably as the type specifier in a variable declaration.


As others have said the principal is: no semicolons after things that use {}, semicolons after everything else.


This isn't quite true. Semi-colons are required after all expressions in rust (even when braces are present).

e.g. `let x = match y { ... };`


Technically here the `;` is for the `let`, which is a statement, not for the match expression within it. The braces are part of the match, not of the let. So the let doesn't end with a block, and thus requires a semicolon.


Weird, I thought it was just something like "If it's an expression, use a semicolon otherwise you're returning it".

Yet everyone here is making a distinction between blocks and not-blocks. Is "my rule" better?

Furthermore, if you say the semicolon is for the let I think it misleads people. Eg if you do `match foo { .. }`, with no let and no semicolon (which is what that rule would suggest), you're actually returning the value of the match. Same goes for a non-match block, too. Eg, `{ .. }` will return the contents. So if you want to prevent that, you use a semicolon. `{ .. };`.

Am I missing something? Why are so many people describing it with the block vs semicolon thing?


> Weird, I thought it was just something like "If it's an expression, use a semicolon otherwise you're returning it".

This is a common misconception, but it isn't true.

Rust is an expression-oriented language. This means that most things are expressions, and evaluate to some kind of value. However, there are also statements. "Item declarations" (stuff like defining structs, etc) and let statements are the two most common kinds of statements. However, there's also an "expression statement", where you can take any expression, add ; to it, and it becomes a statement rather than an expression.

A block has the following grammar:

  BlockExpression :
     {
        InnerAttribute*
        Statements?
     }

  Statements :
        Statement+
     | Statement+ ExpressionWithoutBlock
     | ExpressionWithoutBlock
A block is made of (leaving some things out for simplicity) zero or more statements, where statements is either one or more statements, one or more statements and an expression, or an expression.

Note that blocks are themselves expressions, and so evaluate to a value. The only way that you get "no semicolon for return" is when the expression is in this tail position, when its value is the value of the whole block.

... does that make sense? Perusing https://doc.rust-lang.org/reference/statements-and-expressio... might help.


TBH I thought it made sense, but I'm still confused on everyone elses description lol.

I feel like what you said is what I said, but with more accuracy and depth. Eg, if my block was:

  {
    foo();
    bar()
    baz();
  }
My statement holds true, no? It's obviously a syntax problem, since I'm trying to define a statement after I define an expression (which would be trying to execute code after a return, effectively).

So.. I'm not arguing (I trust you to be right lol), but I struggle to understand which part of my statement is inaccurate, beyond the simplifications/etc at least.

To word it differently; I still feel what I said..

> If it's an expression, use a semicolon otherwise you're returning it

seems more accurate as a mental cheatsheet than:

> no semicolons after things that use {}, semicolons after everything else.

Since {}'s can so often result in a value returning, defaulting to not using semicolons just because it's a {} seems odd. I would think focusing on if it's an expression would be easier to understand, no?

Appreciate your time as always Steve :)


It is not 100% clear what specifically you're saying to me, to be honest. All I know is, that in the code above, if you expect bar() to return its value from the block, your mental model of how this stuff works is incorrect.

To be honest, my mental model of all of this is "write code, fix it when the compiler complains"; I rarely think about semicolons, and cargo fmt will remove extraneous ones, so it's sometimes hard for me to go anywhere between "these are the rules of the grammar" and "don't think about it at all". My failing, not yours :)


Apologies for the poorly worded question. Regardless, thanks much as always :)


I don't think it was poorly worded; I'm just chugging some coffee and find some discussions easier than others :)


I think it is better to not think of ; (or lack of ;) as an "active" return: it isn't like the `return` keyword.

If the last statement/expression in a block is an expression not followed by ;, the block evaluates to that expression. Otherwise (such as, the last expression has a ;), the block evaluates to ().

The function "return" behaviour is because function bodies are blocks: a function returns the value of its block (or any `return`).


You’re correct. Other folks seem to be using non-Rust mental models for semicolons.


No they're not, see steve's explanation above.

Putting a semicolon after an expression makes it into a statement, which are unit-valued, which is why the expression's value gets suppressed. It's a subset of "statements not ending with blocks" (since an expression-statement doesn't take a statement-block even if the expression itself has one).


But my comment was in reply to:

> no semicolons after things that use {}, semicolons after everything else.

Which seems fundamentally flawed for a cheatsheet. Unless you never intend to return anything with a bracket, I guess.


Indeed, hence me saying "things that use {}" (like struct {} and trait {}), not "after {}". :)


On the practical side, assuming you set up your editor to run rustfmt on save, then you don't have to think about it because rustfmt will insert delete semicolons if you get it wrong, and then you end up learning anyway.


Semicolons after statements.

Optional after expressions.


Ralf Biedert, thanks so much for this! I've been learning Rust via the Rust Book for the past few months and this will help so, so much - fantastic work.


I know everyone says how good Rust's documentation is but I tried learning Rust with The Rust Book and found it frustrating: too long and wordy on the easy bits and without useful insight on the hard bits. I ended up buying Programming Rust by Jim Blandy [0] on a recommendation from HN comments and found it must easier to learn from. I'm already familiar with several other languages, which that book assumes, so your milage may vary.

[0] https://www.amazon.co.uk/Programming-Rust-Jim-Blandy/dp/1491...


You’re not alone. I found the Rust book very hard going, whereas Programming Rust was just the right amount of rigor and interesting examples for me.


This is why I'm glad we have both; I don't think one resource could ever satisfy everyone. Pumped to see Rust in Action getting closer to publication too!


I just bought Rust in Action a couple weeks ago (after having gone up to chapter 11 in the No Starch book). It's definitely good to have both. I'll probably do 1/2 the new book, finish the 1st one and then finish the new one.

I did pretty much the same thing with Dave Thomas's Programming Elixir book, bailing halfway through, using a 2nd resource to consolidate, and then returning to finish it.

I like learning Rust so far. The main thing I wonder is what kinds of projects are good to do while learning. I went from Node to Rails to Phoenix and normally I just rewrite web apps I've previously created in the language I'm learning. With Rust, it feels like I should build something different, something lower-level like a tool, an emulator or a 2D game.


> I like learning Rust so far. The main thing I wonder is what kinds of projects are good to do while learning. I went from Node to Rails to Phoenix and normally I just rewrite web apps I've previously created in the language I'm learning. With Rust, it feels like I should build something different, something lower-level like a tool, an emulator or a 2D game.

If your experience is web apps, I would stick with that; Rust has a great web app story in the form of at least two mature frameworks.


This is a common issue. You don’t have to go low level; you can build anything, including web apps.


I remember mentioning in a thread here a while back that I so enjoyed flicking through your/Carols' book online that I wished I was learning Rust, though I was unlikely for practical reasons to do so. Well now I am, and that exposure via a pleasurable read was what seeded the idea.

It's true it's not a terse breakneck intro for advanced programmers. But as an experienced developer, I'm enjoying it no less for that. In any field I've been involved in, I've always enjoyed revisiting fundamentals, and in the context of learning a new (and let's be honest, not very easy or familiar) programming language this seems even more appropriate.

Perhaps if I were learning Rust for work I'd want something more distilled to get me started. Even there I'm sure I'd read TRPL at some point. But right now I'm finding it an enjoyable way to get underway for my own interest.


Thanks!


Ah, awesome, another Rust book. I'll keep an eye out for it.

Thanks!


Seconded. I read Programming Rust and it was excellent. Too bad there is no second part. I didn't get too far in the Rust book though.


> I know everyone says how good Rust's documentation is but I tried learning Rust with The Rust Book and found it frustrating: too long and wordy on the easy bits and without useful insight on the hard bits. I ended up buying Programming Rust by Jim Blandy [0] on a recommendation from HN comments and found it must easier to learn from. I'm already familiar with several other languages, which that book assumes, so your milage may vary.

> [0] https://www.amazon.co.uk/Programming-Rust-Jim-Blandy/dp/1491....

Thanks for tip, the Rust Book is working well for me so far but it's good to know of other good options.


> everyone says how good Rust's documentation is

I don't know about everyone else, but when I say that I'm mostly referring to the auto generated documentation you get from Cargo. One of Rust's greatest strengths is having uniform documentation for every project.


Really enjoyed the fact that there was an "Idiomatic Rust" section.


> unsafe {}

> If you need to crash your code in production

heh :-)


The first ' in '' is red and the second one is black. Does the syntax highlighter maybe work on ucs-16 characters wrongly?


Anyone remember when rust had ~ and @?



This is great. Nice work!


Just to be funny, it's a Cheatbook.


Very nice!




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

Search: