|
From Learn Rust in a Month of Lunches by David MacLeod This book is for anyone who wants to learn Rust and maybe doesn’t have a lot of time in their day to do it. |
The Rust language was released only in 2015, and as of 2023 isn’t even a decade old. It’s quite new, but already very popular, appearing just about everywhere you can think of: Windows, Android, the Linux kernel, Amazon Web Services (AWS), Discord, Cloudflare, you name it. It really is incredible how popular Rust has become after less than a decade.
Rust is popular because it gives you almost everything you could want in a language: the speed and control of languages like C or C++, the memory safety of other newer languages like Python, a rich type system that lets you avoid bugs, and a friendly compiler that helps you when you go wrong. It does this with some new ideas that are sometimes different from other languages. That means that there are some new things to learn, and you can’t just “figure it out as you go along”. Rust is a language that you have to think about for a while to understand.
In Rust, you get the hangover first
So Rust is a language that is famously difficult to learn. But I don’t agree that Rust is difficult. Programming itself is difficult. Rust just shows you these difficulties when you are writing your code, not after you start running it. That’s where this saying comes from: “In Rust, you get the hangover first”. In many other languages the ‘party’ starts first: your code compiles, and looks great! Then you run your code, and there’s a lot to debug. That’s when you get the hangover.
So the ‘hangover’ in Rust is because you have to satisfy the compiler that you are writing correct code. If your code doesn’t satisfy the compiler, it won’t run. You can’t give it one type when it expects another, you have to handle possible errors, you have to decide what to do when a value might be missing. But as you do that, the compiler gives you hints and suggestions to fix your code so that it will run. It’s tough work but the compiler tries to guide you through the way. And when your code finally compiles, it works great.
Rust as the first language
And in fact, because of that Rust was the first language that I was properly able to learn. I loved how friendly the compiler was when my code didn’t compile. The compiler felt like a teacher or a co-programmer. It was also interesting how the errors taught me about how computers use memory. Rust wasn’t just a language that let me build software, it was a language that taught me more about computers than I knew before. The more I used it the more I wanted to know, and that’s why I was able to learn Rust as my first language. I hope this book will help others learn it too, even if Rust is their first programming language.
Making Rust easy
Rust in a Month of Lunches has a single goal: to be the absolute easiest way for anyone to learn Rust.
This book uses three main ways to make learning Rust as easy as possible.
The language in the book is not difficult.
Rust in a Month of Lunches is written in simple English. I like to think of the book’s target audience as these types of people:
- People who are ambitious and want to learn Rust as quickly as possible. The simple English used in the book gets out of your way and lets you focus more on Rust itself.
- People with English as a second language. Most developers know English well enough that reading documentation is easy enough, but a full book can be a bit of a burden for some.
- People that are curious but don’t have enough time in the day, and just want to get to the information. Maybe you only have 30 minutes a day to devote to Rust. Without any flowery language, you can use those 30 minutes as effectively as possible to get to the information you want.
- People who have read another introductory Rust book and want to go over the basics again with something new. And finally:
- People that have tried to learn Rust, but it still hasn’t clicked yet. Hopefully, this book will be the one that does the trick!
A Rust-first approach: learning Rust as your first programming language
When Rust was released in 2015, it had to convince the world that it was worth learning. A lot of books then compared Rust to languages like C++ and C, because Rust is a good alternative language for C++ and C programmers. Rust books and websites were also written for people coming from Java, C#, and other such languages.
Today, however, a lot more people are now learning Rust as a first language. For those people, a book that starts with examples in other languages is just going to be confusing. This book also doesn’t assume that you know general programming terminology: words like generics, pointers, stack and heap memory, arguments, expressions, concurrency, and so on. All of these terms are explained one by one.
You don’t need to install Rust to get started.
Almost all of this book is written using the online Rust Playground, which requires nothing to install. You can of course use VS Code or some other IDE you have installed, but you don’t need to. The book intends to be easy in this sense too: you should be able to learn most of the language just by opening up a tab in your browser.
So, the book is intended to be an easy way to learn Rust, but here’s another interesting fact that seems odd when you first think about it: Rust isn’t that hard.
Rust itself is kind of easy
Seriously! Well, sort of. Yes, it’s complex and takes a lot of work to learn. Yes, most people that learn Rust have frustrating days (sometimes unbearably frustrating days) where they just want their code to compile and don’t understand what to do.
But this period does not last forever, and after it is over Rust becomes easier because it starts doing a lot of the thinking for you. Rust is the type of language that allows junior developers to start working on an existing code base with confidence because for the most part, it simply won’t compile if there’s a problem with your code.
Sometimes you hear stories about junior developers that join a company: they see a code base and ask if they can make a change, but the senior developers say not to touch it “because it’s working and who knows what will happen if you make a change”. Rust isn’t like that; it won’t let changes that break things compile!
That makes contributing and refactoring code…well, easy. If you watch Rust live streams on YouTube or Twitch you’ll see this happen a lot. The streamer will make a bunch of changes to some existing code, then say “Okay, let’s see what breaks.” The compiler gives a few dozen messages showing what parts don’t work anymore, and then the streamer hunts them down one by one and makes the necessary changes until it compiles again — usually in just a few minutes. Not a lot of languages can do that.
Rust is like a critical spouse
My favorite analogy for Rust is that of a critical but helpful spouse. Imagine you have a job interview and are getting ready to head out the door and ask your spouse how you look. Let’s see how two types of spouses treat you: the lenient language spouse and the strict Rust spouse.
The lenient language spouse sees you going out the door and calls out: “You look great, honey! Hope the interview goes well.”
And off you go! You’re feeling good. But maybe you don’t look great and don’t realize it. Maybe you forgot to prepare a number of important things for the interview. If you’re an expert in interviews you’ll do fine, but if not, you might be in trouble.
The Rust spouse isn’t so lenient, and won’t even let you out the door: “You’re going out wearing that? It’s too hot today, you’ll be sweating by the time you get in. Put on that suit with the lighter fabric.”
You change your suit.
The Rust spouse looks at you and says: “The suit you just changed into doesn’t match your socks. You need to change to grey socks.”
You grumble and go change your socks.
The Rust spouse still isn’t satisfied: “It’s windy today and it’s a 500 meter walk from the parking lot to the company. Your hair is going to be messy by the time you get there. Put some gel in.”
You go back to the bathroom and put some gel in your hair.
Rust spouse: “You still can’t go. The parking lot you’ll be using was built a long time ago and doesn’t take credit cards. You need $2.50 in change for the machine. Find some change.”
Sigh. You go and look around for some loose change. Finally you gather $2.50 together.
This repeats and repeats another ten times. You’re starting to get annoyed, but you know your spouse is right.
You make yet another change. Is it the last one?
Now your Rust spouse looks you up and down, thinks a bit, and then says: “…Fine. Off you go.”
Yes! Finally! That was a lot of work.
And you head out the door, still a bit frustrated by all the changes you had to make. But you walk by a window and see your reflection. You look great! It’s windy today but your hair isn’t being blown around. You pull into the parking lot and put in the $2.50 – just the right amount of change.
You look around and see someone else arriving for the interview in a suit that’s too heavy and is already sweating. His socks don’t match the suit. He only has a credit card and is trying to find a store nearby to get some change. He starts walking off to the store, his hair in a mess as the wind blows it every which way. But not you — your spouse did half of the work for you before you even started.
Heavy lifting
So in that sense, Rust is a really easy language, as the compiler does a lot of heavy lifting for you.
And if you think about it, programs live at run time, but programmers live at compile time — the time before a program starts. If your code compiles, you hit run and hope for the best. You can’t control the program anymore once it starts.
If your language isn’t strict at compile time, most of the possible errors will happen at run time instead and now you have to debug them. Rust is as strict as possible at compile time, which is where you the programmer live. So Rust teaches you as much as it can about your program before you even run it.
Okay, what does this actually look like in practice? Let’s take a look at a real example. We’ll go to the Playground and write some incorrect Rust code and see what happens.
Some tips first:
- Run your code with Run
- Change Debug to Release if you want your code to be faster. Debug: compiles faster, runs slower, and contains debug information. Release: compiles slower, runs much faster, removes debug information.
- Click on Share to get a URL link. You can use that to share your code if you want help. After you click share, you can click on `Open a new thread in the Rust user forum` to ask people there for help right away.
- Tools: Rustfmt will format your code nicely.
- Tools: Clippy will give you extra information about how to make your code better.
- Config: here you can change your theme to dark mode so you can work at night, and many other configurations.
Great, now let’s write some incorrect code. We’ll try to make a String, then push a single character to it and print it out. This is just to show what Rust’s compiler messages look like – you’ll learn what all of this means soon.
fn main() { ⚠️ let my_name: String = "Dave"; my_name.push("!"); println!("{}" my_name); }
This is pretty good for a first try at Rust, but it’s not correct yet. What does the Rust compiler have to say about that? Quite a bit, in fact. It gives you three suggestions:
error: expected `,`, found `my_name` | 4 | println!("{}" my_name); | ^^^^^^^ expected `,` error[E0308]: mismatched types --> src/main.rs:2:27 | 2 | let my_name: String = "Dave"; | ------ ^^^^^^- help: try using a conversion method: `.to_string()` | | | | | expected struct `String`, found `&str` | expected due to this
error[E0308]: mismatched types --> src/main.rs:3:18 | 3 | my_name.push("!"); | ---- ^^^ expected `char`, found `&str` | | | arguments to this function are incorrect | help: if you meant to write a `char` literal, use single quotes | 3 | my_name.push('!'); | ~~~
If you do what the compiler suggests, then it will look like this:
fn main() { let my_name: String = "Dave".to_string(); my_name.push('!'); println!("{}", my_name); }
When you hit run again, you’ll see the compiler now has a little more to say:
error[E0596]: cannot borrow `my_name` as mutable, as it is not declared as mutable --> src/main.rs:3:5 | 2 | let my_name: String = "Dave".to_string(); | ------- help: consider changing this to be mutable: `mut my_name` 3 | my_name.push('!'); | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable
If you follow its advice here, then you’ll end up with this code:
fn main() { let mut my_name: String = "Dave".to_string(); my_name.push('!'); println!("{}", my_name); }
And it works! That’s the combination of strictness and helpfulness that the Rust compiler is famous for.
What will you learn from this book?
Learn Rust in a Month of Lunches will teach you to:
- Understand and be comfortable writing software in Rust
- Understand the messages from the compiler, borrow checker and clippy to know how to write code that compiles and is idiomatic
- Be able to make decisions on the right type to use depending on the context (e.g. single threaded vs. multiple threads, one collection type vs. another collection type)
- Have a broad overview of the Rust standard library and its most commonly used items
- Be familiar with the most commonly used external crates (libraries). (Rust is a language with a relatively small standard library so even common tasks usually require using a few external crates)
- Be able to work with crates that use async Rust
- Be able to write simple declarative macros
Let’s get started!! You can check out the book here.