Skip to content

Week 1 Rust introduction #272

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

Closed
wants to merge 1 commit into from
Closed
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
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions .idea/MyRustWay.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion book/src/01_intro/01_syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,6 @@ Every single value in Rust has a type and that type must be known to the compile

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
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.
12 changes: 6 additions & 6 deletions book/src/02_basic_calculator/01_integers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ 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 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.).
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 equivalent type for signed integer is `i32`, where the `i` stands for integer (i.e. any integer, positive or
Expand All @@ -29,12 +29,12 @@ negative).
### Bit width

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.
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 the same number of bits, a signed integer (`i32`) can represent numbers from `-2^31` to `2^31 - 1`
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)).\
The maximum value for `i32` is smaller than the maximum value for `u32` because one bit is used to represent
Expand Down Expand Up @@ -69,7 +69,7 @@ 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 Down
2 changes: 1 addition & 1 deletion book/src/02_basic_calculator/06_while.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ while <condition> {
}
```

For example, we might want to sum the numbers from 1 to 5:
For example, we might want to sum the NUMBERS from 1 to 5:

```rust
let sum = 0;
Expand Down
10 changes: 5 additions & 5 deletions book/src/02_basic_calculator/07_for.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ for <element> in <iterator> {

## Ranges

Rust's standard library provides **range** type that can be used to iterate over a sequence of numbers[^weird-ranges].
Rust's standard library provides **range** type that can be used to iterate over a sequence of NUMBERS[^weird-ranges].

For example, if we want to sum the numbers from 1 to 5:
For example, if we want to sum the NUMBERS from 1 to 5:

```rust
let mut sum = 0;
Expand All @@ -32,9 +32,9 @@ Every time the loop runs, `i` will be assigned the next value in the range befor

There are five kinds of ranges in Rust:

- `1..5`: A (half-open) range. It includes all numbers from 1 to 4. It doesn't include the last value, 5.
- `1..=5`: An inclusive range. It includes all numbers from 1 to 5. It includes the last value, 5.
- `1..`: An open-ended range. It includes all numbers from 1 to infinity (well, until the maximum value of the integer type).
- `1..5`: A (half-open) range. It includes all NUMBERS from 1 to 4. It doesn't include the last value, 5.
- `1..=5`: An inclusive range. It includes all NUMBERS from 1 to 5. It includes the last value, 5.
- `1..`: An open-ended range. It includes all NUMBERS from 1 to infinity (well, until the maximum value of the integer type).
- `..5`: A range that starts at the minimum value for the integer type and ends at 4. It doesn't include the last value, 5.
- `..=5`: A range that starts at the minimum value for the integer type and ends at 5. It includes the last value, 5.

Expand Down
2 changes: 1 addition & 1 deletion book/src/02_basic_calculator/08_overflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ But the _mathematically correct result_ doesn't fit into that integer type!
> The `speed` function you wrote in the ["Variables" section](02_variables.md) underflowed for some input
> combinations.
> E.g. if `end` is smaller than `start`, `end - start` will underflow the `u32` type since the result is supposed
> to be negative but `u32` can't represent negative numbers.
> to be negative but `u32` can't represent negative NUMBERS.

## No automatic promotion

Expand Down
22 changes: 11 additions & 11 deletions book/src/06_ticket_management/01_arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Here's how you can define an array:

```rust
// Array type syntax: [ <type> ; <number of elements> ]
let numbers: [u32; 3] = [1, 2, 3];
let NUMBERS: [u32; 3] = [1, 2, 3];
```

This creates an array of 3 integers, initialized with the values `1`, `2`, and `3`.\
Expand All @@ -25,7 +25,7 @@ If all array elements are the same, you can use a shorter syntax to initialize i

```rust
// [ <value> ; <number of elements> ]
let numbers: [u32; 3] = [1; 3];
let NUMBERS: [u32; 3] = [1; 3];
```

`[1; 3]` creates an array of three elements, all equal to `1`.
Expand All @@ -35,9 +35,9 @@ let numbers: [u32; 3] = [1; 3];
You can access elements of an array using square brackets:

```rust
let first = numbers[0];
let second = numbers[1];
let third = numbers[2];
let first = NUMBERS[0];
let second = NUMBERS[1];
let third = NUMBERS[2];
```

The index must be of type `usize`.\
Expand All @@ -49,8 +49,8 @@ tuples/tuple-like variants.
If you try to access an element that's out of bounds, Rust will panic:

```rust
let numbers: [u32; 3] = [1, 2, 3];
let fourth = numbers[3]; // This will panic
let NUMBERS: [u32; 3] = [1, 2, 3];
let fourth = NUMBERS[3]; // This will panic
```

This is enforced at runtime using **bounds checking**. It comes with a small performance overhead, but it's how
Expand All @@ -61,11 +61,11 @@ more about this later on.
If you don't want to panic, you can use the `get` method, which returns an `Option<&T>`:

```rust
let numbers: [u32; 3] = [1, 2, 3];
assert_eq!(numbers.get(0), Some(&1));
let NUMBERS: [u32; 3] = [1, 2, 3];
assert_eq!(NUMBERS.get(0), Some(&1));
// You get a `None` if you try to access an out-of-bounds index
// rather than a panic.
assert_eq!(numbers.get(3), None);
assert_eq!(NUMBERS.get(3), None);
```

### Performance
Expand All @@ -74,7 +74,7 @@ Since the size of an array is known at compile-time, the compiler can allocate t
If you run the following code:

```rust
let numbers: [u32; 3] = [1, 2, 3];
let NUMBERS: [u32; 3] = [1, 2, 3];
```

You'll get the following memory layout:
Expand Down
34 changes: 17 additions & 17 deletions book/src/06_ticket_management/02_vec.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ If you try to create an array with a size that's only known at runtime, you'll g

```rust
let n = 10;
let numbers: [u32; n];
let NUMBERS: [u32; n];
```

```text
error[E0435]: attempt to use a non-constant value in a constant
--> src/main.rs:3:20
|
2 | let n = 10;
3 | let numbers: [u32; n];
3 | let NUMBERS: [u32; n];
| ^ non-constant value
```

Expand All @@ -26,44 +26,44 @@ This is where `Vec` comes in.
You can create an empty array using the `Vec::new` function:

```rust
let mut numbers: Vec<u32> = Vec::new();
let mut NUMBERS: Vec<u32> = Vec::new();
```

You would then push elements into the vector using the `push` method:

```rust
numbers.push(1);
numbers.push(2);
numbers.push(3);
NUMBERS.push(1);
NUMBERS.push(2);
NUMBERS.push(3);
```

New values are added to the end of the vector.\
You can also create an initialized vector using the `vec!` macro, if you know the values at creation time:

```rust
let numbers = vec![1, 2, 3];
let NUMBERS = vec![1, 2, 3];
```

## Accessing elements

The syntax for accessing elements is the same as with arrays:

```rust
let numbers = vec![1, 2, 3];
let first = numbers[0];
let second = numbers[1];
let third = numbers[2];
let NUMBERS = vec![1, 2, 3];
let first = NUMBERS[0];
let second = NUMBERS[1];
let third = NUMBERS[2];
```

The index must be of type `usize`.\
You can also use the `get` method, which returns an `Option<&T>`:

```rust
let numbers = vec![1, 2, 3];
assert_eq!(numbers.get(0), Some(&1));
let NUMBERS = vec![1, 2, 3];
assert_eq!(NUMBERS.get(0), Some(&1));
// You get a `None` if you try to access an out-of-bounds index
// rather than a panic.
assert_eq!(numbers.get(3), None);
assert_eq!(NUMBERS.get(3), None);
```

Access is bounds-checked, just like element access with arrays. It has O(1) complexity.
Expand All @@ -76,9 +76,9 @@ When you create a `Vec`, it allocates memory on the heap to store the elements.
If you run the following code:

```rust
let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);
let mut NUMBERS = Vec::with_capacity(3);
NUMBERS.push(1);
NUMBERS.push(2);
```

you'll get the following memory layout:
Expand Down
10 changes: 5 additions & 5 deletions book/src/06_ticket_management/03_resizing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ We said that `Vec` is a "growable" vector type, but what does that mean?
What happens if you try to insert an element into a `Vec` that's already at maximum capacity?

```rust
let mut numbers = Vec::with_capacity(3);
numbers.push(1);
numbers.push(2);
numbers.push(3); // Max capacity reached
numbers.push(4); // What happens here?
let mut NUMBERS = Vec::with_capacity(3);
NUMBERS.push(1);
NUMBERS.push(2);
NUMBERS.push(3); // Max capacity reached
NUMBERS.push(4); // What happens here?
```

The `Vec` will **resize** itself.\
Expand Down
10 changes: 5 additions & 5 deletions book/src/06_ticket_management/05_iter.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Most collections expose a method called `.iter()` that returns an iterator over
For example:

```rust
let numbers: Vec<u32> = vec![1, 2];
let NUMBERS: Vec<u32> = vec![1, 2];
// `n` has type `&u32` here
for n in numbers.iter() {
for n in NUMBERS.iter() {
// [...]
}
```
Expand All @@ -25,11 +25,11 @@ In our example above, that would be `&Vec<Ticket>`.\
The standard library does this, that's why the following code works:

```rust
let numbers: Vec<u32> = vec![1, 2];
let NUMBERS: Vec<u32> = vec![1, 2];
// `n` has type `&u32` here
// We didn't have to call `.iter()` explicitly
// It was enough to use `&numbers` in the `for` loop
for n in &numbers {
// It was enough to use `&NUMBERS` in the `for` loop
for n in &NUMBERS {
// [...]
}
```
Expand Down
14 changes: 7 additions & 7 deletions book/src/06_ticket_management/07_combinators.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ These methods are called **combinators**.\
They are usually **chained** together to create complex transformations in a concise and readable way:

```rust
let numbers = vec![1, 2, 3, 4, 5];
// The sum of the squares of the even numbers
let outcome: u32 = numbers.iter()
let NUMBERS = vec![1, 2, 3, 4, 5];
// The sum of the squares of the even NUMBERS
let outcome: u32 = NUMBERS.iter()
.filter(|&n| n % 2 == 0)
.map(|&n| n * n)
.sum();
Expand Down Expand Up @@ -76,11 +76,11 @@ You either iterate over the transformed values using a `for` loop, or you collec
The latter is done using the `collect` method.\
`collect` consumes the iterator and collects its elements into a collection of your choice.

For example, you can collect the squares of the even numbers into a `Vec`:
For example, you can collect the squares of the even NUMBERS into a `Vec`:

```rust
let numbers = vec![1, 2, 3, 4, 5];
let squares_of_evens: Vec<u32> = numbers.iter()
let NUMBERS = vec![1, 2, 3, 4, 5];
let squares_of_evens: Vec<u32> = NUMBERS.iter()
.filter(|&n| n % 2 == 0)
.map(|&n| n * n)
.collect();
Expand All @@ -92,7 +92,7 @@ In the example above, we annotated the type of `squares_of_evens` to be `Vec<u32
Alternatively, you can use the **turbofish syntax** to specify the type:

```rust
let squares_of_evens = numbers.iter()
let squares_of_evens = NUMBERS.iter()
.filter(|&n| n % 2 == 0)
.map(|&n| n * n)
// Turbofish syntax: `<method_name>::<type>()`
Expand Down
Loading