100 exercises to learn Rust

This commit is contained in:
LukeMathWalker
2024-05-12 22:21:03 +02:00
commit 5edebf6cf2
309 changed files with 13173 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
# Welcome
Welcome to **"100 Exercises To Learn Rust"**!
This course will teach you Rust's core concepts, one exercise at a time.
In roughly 100 exercises, you'll go from knowing nothing about Rust to feeling productive on your own.
## Structure
Each section in this course introduces a new concept or feature of the Rust language.
To verify your understanding, each section is paired with an exercise that you need to solve.
Each exercise is structured as a Rust package, located in the `exercises` folder.
The package contains the exercise itself, instructions on what to do (in `src/lib.rs`), and a test suite to
automatically verify your solution.
### `wr`, the workshop runner
To navigate through the course, you will be using the `wr` CLI (short for "workshop runner").
Install it with:
```bash
cargo install --locked workshop-runner
```
In a new terminal, navigate back to the top-level folder of the repository.
Run the `wr` command to start the course:
```bash
wr
```
`wr` will verify the solution to the current exercise.
Don't move on to the next section until you've solved the exercise for the current one.
Enjoy the course!
## References
- The exercise for this section is located in `exercises/01_intro/00_welcome`

View File

@@ -0,0 +1,112 @@
# Syntax
The previous task doesn't even qualify as an exercise, but it already exposed you to quite a bit of Rust **syntax**.
Let's review the key bits!
> We won't cover every single detail of Rust's syntax used in the previous exercise.
> Instead, we'll cover _just enough_ to keep going without getting stuck in the details.
> One step at a time!
## Comments
You can use `//` for single-line comments:
```rust
// This is a single-line comment
// Followed by another single-line comment
```
## Functions
Functions in Rust are defined using the `fn` keyword, followed by the function's name, its input parameters, and its
return type.
The function's body is enclosed in curly braces `{}`.
In previous exercise, you saw the `greeting` function:
```rust
// `fn` <function_name> ( <input parameters> ) -> <return_type> { <body> }
fn greeting() -> &'static str {
// TODO: fix me 👇
"I'm ready to __!"
}
```
`greeting` has no input parameters and returns a reference to a string slice (`&'static str`).
### Return type
The return type can be omitted from the signature if the function doesn't return anything (i.e. if it returns `()`,
Rust's unit type).
That's what happened with the `test_welcome` function:
```rust
fn test_welcome() {
assert_eq!(greeting(), "I'm ready to learn Rust!");
}
```
The above is equivalent to:
```rust
// Spelling out the unit return type explicitly
// 👇
fn test_welcome() -> () {
assert_eq!(greeting(), "I'm ready to learn Rust!");
}
```
### Returning values
The last expression in a function is implicitly returned:
```rust
fn greeting() -> &'static str {
// This is the last expression in the function
// Therefore its value is returned by `greeting`
"I'm ready to learn Rust!"
}
```
You can also use the `return` keyword to return a value early:
```rust
fn greeting() -> &'static str {
// Notice the semicolon at the end of the line!
return "I'm ready to learn Rust!";
}
```
It is considered idiomatic to omit the `return` keyword when possible.
### Input parameters
Input parameters are declared inside the parentheses `()` that follow the function's name.
Each parameter is declared with its name, followed by a colon `:`, followed by its type.
For example, the `greet` function below takes a `name` parameter of type `&str` (a "string slice"):
```rust
// An input parameter
// 👇
fn greet(name: &str) -> String {
format!("Hello, {}!", name)
}
```
If there are multiple input parameters, they must be separated with commas.
### Type annotations
Since we've been mentioned "types" a few times, let's state it clearly: Rust is a **statically typed language**.
Every single value in Rust has a type and that type must be known to the compiler at compile-time.
Types are a form of **static analysis**.
You can think of a type as a **tag** that the compiler attaches to every value in your program. Depending on the
tag, the compiler can enforce different rules—e.g. you can't add a string to a number, but you can add two numbers
together.
If leveraged correctly, types can prevent whole classes of runtime bugs.
## References
- The exercise for this section is located in `exercises/01_intro/01_syntax`