Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formatter #51

Merged
merged 4 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ on:
- main

jobs:
formatter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: dprint/[email protected]

check-links:
runs-on: ubuntu-latest
steps:
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Learn Rust, one exercise at a time

You've heard about Rust, but you never had the chance to try it out?
You've heard about Rust, but you never had the chance to try it out?\
This course is for you!

You'll learn Rust by solving 100 exercises.
You'll learn Rust by solving 100 exercises.\
You'll go from knowing nothing about Rust to being able to start
writing your own programs, one exercise at a time.

> [!NOTE]
> This course has been written by [Mainmatter](https://mainmatter.com/rust-consulting/).
> It's one of the trainings in [our portfolio of Rust workshops](https://mainmatter.com/services/workshops/rust/).
> This course has been written by [Mainmatter](https://mainmatter.com/rust-consulting/).\
> It's one of the trainings in [our portfolio of Rust workshops](https://mainmatter.com/services/workshops/rust/).\
> Check out our [landing page](https://mainmatter.com/rust-consulting/) if you're looking for Rust consulting or
> training!

Expand All @@ -20,7 +20,7 @@ to get started with the course.

## Requirements

- **Rust** (follow instructions [here](https://www.rust-lang.org/tools/install)).
- **Rust** (follow instructions [here](https://www.rust-lang.org/tools/install)).\
If `rustup` is already installed on your system, run `rustup update` (or another appropriate command depending on how
you installed Rust on your system)
to make sure you're running on the latest stable version.
Expand Down
52 changes: 26 additions & 26 deletions book/src/01_intro/00_welcome.md
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
# Welcome

Welcome to **"100 Exercises To Learn Rust"**!
Welcome to **"100 Exercises To Learn Rust"**!

This course will teach you Rust's core concepts, one exercise at a time.
This course will teach you Rust's core concepts, one exercise at a time.\
You'll learn about Rust's syntax, its type system, its standard library, and its ecosystem.

We don't assume any prior knowledge of Rust, but we assume you know at least
another programming language.
another programming language.\
We also don't assume any prior knowledge of systems programming or memory management. Those
topics will be covered in the course.

In other words, we'll be starting from scratch!
In other words, we'll be starting from scratch!\
You'll build up your Rust knowledge in small, manageable steps.
By the end of the course, you will have solved ~100 exercises, enough to
feel comfortable working on small to medium-sized Rust projects.

## Methodology

This course is based on the "learn by doing" principle.
It has been designed to be interactive and hands-on.
This course is based on the "learn by doing" principle.\
It has been designed to be interactive and hands-on.

[Mainmatter](https://mainmatter.com/rust-consulting/) developed this course
to be delivered in a classroom setting, over 4 days: each attendee advances
through the lessons at their own pace, with an experienced instructor providing
guidance, answering questions and diving deeper into the topics as needed.
to be delivered in a classroom setting, over 4 days: each attendee advances
through the lessons at their own pace, with an experienced instructor providing
guidance, answering questions and diving deeper into the topics as needed.\
If you're interested in attending one of our training sessions, or if you'd like to
bring this course to your company, please [get in touch](https://mainmatter.com/contact/).

You can also follow the course on your own, but we recommend you find a friend or
a mentor to help you along the way should you get stuck. You can
also find solutions to all exercises in the
You can also follow the course on your own, but we recommend you find a friend or
a mentor to help you along the way should you get stuck. You can
also find solutions to all exercises in the
[`solutions` branch of the GitHub repository](https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions).

## Structure

On the left side of the screen, you can see that the course is divided into sections.
Each section 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 section 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.

You can find the exercises in the
[companion GitHub repository](https://github.com/mainmatter/100-exercises-to-learn-rust).
You can find the exercises in the
[companion GitHub repository](https://github.com/mainmatter/100-exercises-to-learn-rust).\
Before starting the course, make sure to clone the repository to your local machine:

```bash
Expand All @@ -60,13 +60,13 @@ git checkout -b my-solutions

All exercises are located in the `exercises` folder.
Each exercise is structured as a Rust package.
The package contains the exercise itself, instructions on what to do (in `src/lib.rs`), and a test suite to
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 verify your solutions, we've provided a tool that will guide you through the course.
It is the `wr` CLI (short for "workshop runner").
It is the `wr` CLI (short for "workshop runner").
Install it with:

```bash
Expand All @@ -80,10 +80,10 @@ Run the `wr` command to start the course:
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.
`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.

> We recommend committing your solutions to Git as you progress through the course,
> We recommend committing your solutions to Git as you progress through the course,
> so you can easily track your progress and "restart" from a known point if needed.

Enjoy the course!
Expand All @@ -95,10 +95,10 @@ Enjoy the course!
## Author

This course was written by [Luca Palmieri](https://www.lpalmieri.com/), Principal Engineering
Consultant at [Mainmatter](https://mainmatter.com/rust-consulting/).
Luca has been working with Rust since 2018, initially at TrueLayer and then at AWS.
Luca is the author of ["Zero to Production in Rust"](https://zero2prod.com),
the go-to resource for learning how to build backend applications in Rust.
Consultant at [Mainmatter](https://mainmatter.com/rust-consulting/).\
Luca has been working with Rust since 2018, initially at TrueLayer and then at AWS.\
Luca is the author of ["Zero to Production in Rust"](https://zero2prod.com),
the go-to resource for learning how to build backend applications in Rust.\
He is also the author and maintainer of a variety of open-source Rust projects, including
[`cargo-chef`](https://github.com/LukeMathWalker/cargo-chef),
[Pavex](https://pavex.dev) and [`wiremock`](https://github.com/LukeMathWalker/wiremock-rs).
[Pavex](https://pavex.dev) and [`wiremock`](https://github.com/LukeMathWalker/wiremock-rs).
14 changes: 7 additions & 7 deletions book/src/01_intro/01_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

<div class="warning">

Don't jump ahead!
Complete the exercise for the previous section before you start this one.
It's located in `exercises/01_intro/00_welcome`, in the [course GitHub's repository](https://github.com/mainmatter/100-exercises-to-learn-rust).
Don't jump ahead!\
Complete the exercise for the previous section before you start this one.\
It's located in `exercises/01_intro/00_welcome`, in the [course GitHub's repository](https://github.com/mainmatter/100-exercises-to-learn-rust).\
Use [`wr`](00_welcome.md#wr-the-workshop-runner) to start the course and verify your solutions.

</div>

The previous task doesn't even qualify as an exercise, but it already exposed you to quite a bit of Rust **syntax**.
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.
Instead, we'll cover _just enough_ to keep going without getting stuck in the details.\
One step at a time!

## Comments
Expand Down Expand Up @@ -88,7 +88,7 @@ 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.
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"):
Expand All @@ -105,10 +105,10 @@ 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**.
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**.
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.
Expand Down
2 changes: 1 addition & 1 deletion book/src/02_basic_calculator/00_intro.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# A Basic Calculator

In this chapter we'll learn how to use Rust as a **calculator**.
In this chapter we'll learn how to use Rust as a **calculator**.\
It might not sound like much, but it'll give us a chance to cover a lot of Rust's basics, such as:

- How to define and call functions
Expand Down
26 changes: 13 additions & 13 deletions book/src/02_basic_calculator/01_integers.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Types, part 1

In the ["Syntax" section](../01_intro/01_syntax.md) `compute`'s input parameters were of type `u32`.
In the ["Syntax" section](../01_intro/01_syntax.md) `compute`'s input parameters were of type `u32`.\
Let's unpack what that _means_.

## Primitive types
Expand All @@ -18,25 +18,25 @@ An integer is a number that can be written without a fractional component. E.g.

### Signed vs. unsigned

An integer can be **signed** or **unsigned**.
An integer can be **signed** or **unsigned**.\
An unsigned integer can only represent non-negative numbers (i.e. `0` or greater).
A signed integer can represent both positive and negative numbers (e.g. `-1`, `12`, etc.).

The `u` in `u32` stands for **unsigned**.
The `u` in `u32` stands for **unsigned**.\
The equivalent type for signed integer is `i32`, where the `i` stands for integer (i.e. any integer, positive or
negative).

### Bit width

The `32` in `u32` refers to the **number of bits[^bit]** used to represent the number in memory.
The `32` in `u32` refers to the **number of bits[^bit]** used to represent the number in memory.\
The more bits, the larger the range of numbers that can be represented.

Rust supports multiple bit widths for integers: `8`, `16`, `32`, `64`, `128`.

With 32 bits, `u32` can represent numbers from `0` to `2^32 - 1` (a.k.a. [`u32::MAX`](https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.MAX)).
With 32 bits, `u32` can represent numbers from `0` to `2^32 - 1` (a.k.a. [`u32::MAX`](https://doc.rust-lang.org/std/primitive.u32.html#associatedconstant.MAX)).\
With the same number of bits, a signed integer (`i32`) can represent numbers from `-2^31` to `2^31 - 1`
(i.e. from [`i32::MIN`](https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MIN)
to [`i32::MAX`](https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MAX)).
to [`i32::MAX`](https://doc.rust-lang.org/std/primitive.i32.html#associatedconstant.MAX)).\
The maximum value for `i32` is smaller than the maximum value for `u32` because one bit is used to represent
the sign of the number. Check out the [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement)
representation for more details on how signed integers are represented in memory.
Expand All @@ -46,7 +46,7 @@ representation for more details on how signed integers are represented in memory
Combining the two variables (signed/unsigned and bit width), we get the following integer types:

| Bit width | Signed | Unsigned |
|-----------|--------|----------|
| --------- | ------ | -------- |
| 8-bit | `i8` | `u8` |
| 16-bit | `i16` | `u16` |
| 32-bit | `i32` | `u32` |
Expand All @@ -55,21 +55,21 @@ Combining the two variables (signed/unsigned and bit width), we get the followin

## Literals

A **literal** is a notation for representing a fixed value in source code.
A **literal** is a notation for representing a fixed value in source code.\
For example, `42` is a Rust literal for the number forty-two.

### Type annotations for literals

But all values in Rust have a type, so... what's the type of `42`?

The Rust compiler will try to infer the type of a literal based on how it's used.
If you don't provide any context, the compiler will default to `i32` for integer literals.
The Rust compiler will try to infer the type of a literal based on how it's used.\
If you don't provide any context, the compiler will default to `i32` for integer literals.\
If you want to use a different type, you can add the desired integer type as a suffix—e.g. `2u64` is a 2 that's
explicitly typed as a `u64`.

### Underscores in literals

You can use underscores `_` to improve the readability of large numbers.
You can use underscores `_` to improve the readability of large numbers.\
For example, `1_000_000` is the same as `1000000`.

## Arithmetic operators
Expand All @@ -82,7 +82,7 @@ Rust supports the following arithmetic operators[^traits] for integers:
- `/` for division
- `%` for remainder

Precedence and associativity rules for these operators are the same as in mathematics.
Precedence and associativity rules for these operators are the same as in mathematics.\
You can use parentheses to override the default precedence. E.g. `2 * (3 + 4)`.

> ⚠️ **Warning**
Expand All @@ -92,7 +92,7 @@ You can use parentheses to override the default precedence. E.g. `2 * (3 + 4)`.

## No automatic type coercion

As we discussed in the previous exercise, Rust is a statically typed language.
As we discussed in the previous exercise, Rust is a statically typed language.\
In particular, Rust is quite strict about type coercion. It won't automatically convert a value from one type to
another[^coercion],
even if the conversion is lossless. You have to do it explicitly.
Expand Down
18 changes: 9 additions & 9 deletions book/src/02_basic_calculator/02_variables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Variables

In Rust, you can use the `let` keyword to declare **variables**.
In Rust, you can use the `let` keyword to declare **variables**.\
For example:

```rust
Expand Down Expand Up @@ -35,20 +35,20 @@ let x = 42;
let y: u32 = x;
```

In the example above, we didn't specify the type of `x`.
In the example above, we didn't specify the type of `x`.\
`x` is later assigned to `y`, which is explicitly typed as `u32`. Since Rust doesn't perform automatic type coercion,
the compiler infers the type of `x` to be `u32`—the same as `y` and the only type that will allow the program to compile
without errors.

### Inference limitations

The compiler sometimes needs a little help to infer the correct variable type based on its usage.
The compiler sometimes needs a little help to infer the correct variable type based on its usage.\
In those cases you'll get a compilation error and the compiler will ask you to provide an explicit type hint to
disambiguate the situation.

## Function arguments are variables

Not all heroes wear capes, not all variables are declared with `let`.
Not all heroes wear capes, not all variables are declared with `let`.\
Function arguments are variables too!

```rust
Expand All @@ -57,22 +57,22 @@ fn add_one(x: u32) -> u32 {
}
```

In the example above, `x` is a variable of type `u32`.
In the example above, `x` is a variable of type `u32`.\
The only difference between `x` and a variable declared with `let` is that functions arguments **must** have their type
explicitly declared. The compiler won't infer it for you.
explicitly declared. The compiler won't infer it for you.\
This constraint allows the Rust compiler (and us humans!) to understand the function's signature without having to look
at its implementation. That's a big boost for compilation speed[^speed]!

## Initialization

You don't have to initialize a variable when you declare it.
You don't have to initialize a variable when you declare it.\
For example

```rust
let x: u32;
```

is a valid variable declaration.
is a valid variable declaration.\
However, you must initialize the variable before using it. The compiler will throw an error if you don't:

```rust
Expand Down Expand Up @@ -101,4 +101,4 @@ help: consider assigning a value

- The exercise for this section is located in `exercises/02_basic_calculator/02_variables`

[^speed]: The Rust compiler needs all the help it can get when it comes to compilation speed.
[^speed]: The Rust compiler needs all the help it can get when it comes to compilation speed.
Loading
Loading