Rust Language Cheat Sheet
cheats.rs
cheats.rs
Add shfmt on top and you are good to go.
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.
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).
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.
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.
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.
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?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.)
e.g. `let x = match y { ... };`
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?
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).
> 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.
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.
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 :)
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 :)
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`).
[0] https://www.amazon.co.uk/Programming-Rust-Jim-Blandy/dp/1491...
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.
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.
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!
> [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.
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.
> If you need to crash your code in production
heh :-)