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

Additional explanation to the already existing chapters #19

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
231 changes: 194 additions & 37 deletions lessons/en/chapter_1.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lessons/en/chapter_2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@

and including an end number.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20main()%20%7B%0A%20%20%20%20for%20x%20in%200..5%20%7B%0A%20%20%20%20%20%20%20%20println!(%22%7B%7D%22%2C%20x)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20for%20x%20in%200..%3D5%20%7B%0A%20%20%20%20%20%20%20%20println!(%22%7B%7D%22%2C%20x)%3B%0A%20%20%20%20%7D%0A%7D%0A
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0A%0A++++for+x+in+0..5+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+x%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%0A++++for+x+in+0..%3D5+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+x%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%0A++++let+nums+%3A+%5Bi32%3B+5%5D+%3D+%5B10%2C+-1%2C+9%2C+-80%2C+1%5D%3B%0A++++%0A++++print%21%28%22%7B%7D+%3A+%22%2C+stringify%21%28nums%29%29%3B%0A++++for+el+in+nums+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+el%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%0A++++print%21%28%22%7B%7D+%3A+%22%2C+stringify%21%28nums%29%29%3B%0A++++for+idx+in+0+..+nums.len%28%29+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+nums%5Bidx%5D%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%7D%0A
TrifanBogdan24 marked this conversation as resolved.
Show resolved Hide resolved
- title: match
content_markdown: >
Miss your switch statement? Rust has an incredibly useful keyword
Expand Down
60 changes: 60 additions & 0 deletions lessons/en/chapter_4.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,44 @@
Be a good rustacean and properly use `match` when you can!
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20do_something_that_might_fail(i%3A%20i32)%20-%3E%20Result%3Cf32%2C%20String%3E%20%7B%0A%20%20%20%20if%20i%20%3D%3D%2042%20%7B%0A%20%20%20%20%20%20%20%20Ok(13.0)%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20Err(String%3A%3Afrom(%22this%20is%20not%20the%20right%20number%22))%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20-%3E%20Result%3C()%2C%20String%3E%20%7B%0A%20%20%20%20%2F%2F%20concise%20but%20assumptive%20and%20gets%20ugly%20fast%0A%20%20%20%20let%20v%20%3D%20do_something_that_might_fail(42).unwrap()%3B%0A%20%20%20%20println!(%22found%20%7B%7D%22%2C%20v)%3B%0A%20%20%20%20%0A%20%20%20%20%2F%2F%20this%20will%20panic!%0A%20%20%20%20let%20v%20%3D%20do_something_that_might_fail(1).unwrap()%3B%0A%20%20%20%20println!(%22found%20%7B%7D%22%2C%20v)%3B%0A%20%20%20%20%0A%20%20%20%20Ok(())%0A%7D%0A
- title: if let
content_markdown: >
A much easier way to handle error propagation in Rust
is to use the `if let` block. It basically handles just
the only `match` branch that we are interested to get.

For instance, if we want to get the **error**,
`if let Err(..) = ..` will be used.

Otherwise, `if let Ok(..) = ..` will be chosen
to handle the **success** case.

`if let` can be used only for `Result` and `Option` data types.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+div%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+String%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++return+Err%28String%3A%3Afrom%28%22Invalid+operation%3A+division+by+zero.%22%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0A%0Afn+main%28%29+%7B%0A++++if+let+Ok%28res%29+%3D+div%2810.0%2C+1.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+res%29%3B++++++++%2F%2F+will+be+displayed%0A++++%7D%0A++++%0A++++if+let+Err%28err%29+%3D+div%2810.0%2C+1.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+err%29%3B++++++++%2F%2F+will+NOT+be+displayed%0A++++%7D%0A++++%0A%0A++++if+let+Ok%28res%29+%3D+div%2810.0%2C+0.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+res%29%3B++++++++%2F%2F+will+be+displayed%0A++++%7D%0A++++if+let+Err%28err%29+%3D+div%2810.0%2C+0.0%29+%7B%0A++++++++println%21%28%22%7B%7D%22%2C+err%29%3B++++++++%2F%2F+will+NOT+be+displayed%0A++++%7D%0A%7D%0A
- title: Extracting a Result
content_markdown: >
Another brilliant way to extract a `Result<T, E> { Ok(T), Err(E), }`
is to use the functions `.ok()` and `.err()`, representing the specific variant.

Let's assume we are working with a function whose return type is `Result`, just like in the example.
Using `.ok()` and `.err()` on it will return an `Option`:
- `Some` if the original function had something to return, for results like `Result<i32, i32>`.
- `None` if the original function returned either a `Err(())` or an `Ok(())`, for results like `Result<(), ()>`, `Result<i32, ()>` or `Result<(), i32>`

code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+div1%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+String%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++return+Err%28String%3A%3Afrom%28%22Invalid+operation%3A+division+by+zero.%22%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0A%0Afn+div2%28x%3A+f64%2C+y%3A+f64%29+-%3E+Result%3Cf64%2C+%28%29%3E+%7B%0A++++if+y+%3D%3D+0.0+%7B%0A++++++++%2F%2F+notice+that+the+error+returns+%60None%60%0A++++++++%2F%2F+therefore+will+be+pattern-matched+using+%60%28%29%60%0A++++++++return+Err%28%28%29%29%3B%0A++++%7D%0A++++return+Ok%28x+%2F+y%29%3B%0A%7D%0A%0Afn+main%28%29+%7B%0A++++let+good1+%3D+div1%2810.0%2C+1.0%29%3B%0A++++let+bad1+%3D+div1%2810.0%2C+0.0%29%3B%0A++++%0A++++%2F%2F+Using+.ok%28%29+will+extract+the+Ok+variant%0A++++%2F%2F+.ok%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28value%29+%3D+good1.ok%28%29+%7B%0A++++++++println%21%28%22Result+%28Ok%29%3A+%7B%7D%22%2C+value%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22Result+%28Err%29%22%29%3B%0A++++%7D%0A%0A++++%2F%2F+Using+.err%28%29+to+extract+the+Err+variant%0A++++%2F%2F+.err%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28err%29+%3D+bad1.err%28%29+%7B%0A++++++++println%21%28%22Error%3A+%7B%7D%22%2C+err%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22No+error+%28Ok%29%22%29%3B%0A++++%7D%0A++++%0A++++%0A++++let+good2+%3D+div2%2810.0%2C+1.0%29%3B%0A++++let+bad2+%3D+div2%2810.0%2C+0.0%29%3B%0A++++%0A++++%2F%2F+Using+.ok%28%29+will+extract+the+Ok+variant%0A++++%2F%2F+.ok%28%29+returns+an+Option%3A+Some%0A++++if+let+Some%28value%29+%3D+good2.ok%28%29+%7B%0A++++++++println%21%28%22Result+%28Ok%29%3A+%7B%7D%22%2C+value%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22Result+%28Err%29%22%29%3B%0A++++%7D%0A%0A++++%2F%2F+Using+.err%28%29+to+extract+the+Err+variant%0A++++%2F%2F+.err%28%29+returns+an+Option%3A+None%0A++++if+let+Some%28%28%29%29+%3D+bad2.err%28%29+%7B%0A++++++++println%21%28%22Error+occured%22%29%3B%0A++++%7D+else+%7B%0A++++++++println%21%28%22No+error+%28Ok%29%22%29%3B%0A++++%7D%0A%7D%0A
- title: About panic!
content_markdown: >
In Rust, `panic!` is a macro used to stop the execution of the program
without a recoverable error. When panic occurs, the program immediately
stops, unwinding the stack and cleaning up resources along the way.

Moreover, the code instructions written after `panic!` will no longer be executed.

Usually, `panics` can by avoided by pattern matching the error with `Result`.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0A++++println%21%28%22Reachable.%22%29%3B%0A%0A++++%2F%2F+Generates+a+panic%0A++++panic%21%28%22This+is+a+panic%21%22%29%3B%0A%0A++++%2F%2F+This+line+be+executed%0A++++println%21%28%22Unreachable%22%29%3B%0A%7D%0A
- title: Vectors
content_markdown: >
Some of the most useful generic types are collection types. A vector is a
Expand Down Expand Up @@ -209,6 +247,28 @@
reallocates its data on the heap to have a new fixed list with large capacity.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20main()%20%7B%0A%20%20%20%20%2F%2F%20We%20can%20be%20explicit%20with%20type%0A%20%20%20%20let%20mut%20i32_vec%20%3D%20Vec%3A%3A%3Ci32%3E%3A%3Anew()%3B%20%2F%2F%20turbofish%20%3C3%0A%20%20%20%20i32_vec.push(1)%3B%0A%20%20%20%20i32_vec.push(2)%3B%0A%20%20%20%20i32_vec.push(3)%3B%0A%0A%20%20%20%20%2F%2F%20But%20look%20how%20clever%20Rust%20is%20about%20determining%20the%20type%20automatically%0A%20%20%20%20let%20mut%20float_vec%20%3D%20Vec%3A%3Anew()%3B%0A%20%20%20%20float_vec.push(1.3)%3B%0A%20%20%20%20float_vec.push(2.3)%3B%0A%20%20%20%20float_vec.push(3.4)%3B%0A%0A%20%20%20%20%2F%2F%20That's%20a%20beautiful%20macro!%0A%20%20%20%20let%20string_vec%20%3D%20vec!%5BString%3A%3Afrom(%22Hello%22)%2C%20String%3A%3Afrom(%22World%22)%5D%3B%0A%0A%20%20%20%20for%20word%20in%20string_vec.iter()%20%7B%0A%20%20%20%20%20%20%20%20println!(%22%7B%7D%22%2C%20word)%3B%0A%20%20%20%20%7D%0A%7D%0A
- title: Iterators
content_markdown: >
In Rust, an iterator is an abstraction that decomposed a collection into a sequence of values.

You've seen an iterator before: in the `for` loop
```rust
// 0..5 iterates the values from 0 to 4
for i in 0..5 {
println!("{}", x);
}
```

If you are to modify each element of the collection,
iterators were designed with a very powerful function, `.map()`.

`.map()` and `.iter()` are methods provided by iterators and are commonly
used in working with collections (vectors and String, for instance).

The function `.iter()` iterates over a reference to each element of a collection,
generating a sequence of elements.
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn+main%28%29+%7B%0A++++let+numbers+%3D+vec%21%5B1%2C+2%2C+3%2C+4%2C+5%5D%3B%0A%0A++++%2F%2F+each+element+will+be+modified%0A++++let+doubled%3A+Vec%3Ci32%3E+%3D+numbers.into_iter%28%29.map%28%7Cx%7C+x+*+2%29.collect%28%29%3B%0A++++%0A++++%0A++++%2F%2F+generating+a+sequence+with+all+elements%0A++++for+%26el+in+doubled.iter%28%29+%7B%0A++++++++print%21%28%22%7B%7D+%22%2C+el%29%3B%0A++++%7D%0A++++println%21%28%29%3B%0A%7D%0A
- title: Chapter 4 - Conclusion
content_markdown: >
In one chapter we've learned how much power generic types give us! Don't
Expand Down
33 changes: 33 additions & 0 deletions lessons/en/chapter_7.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,39 @@

That said, Rust implements many programming language features, so that you
might not mind this lacking.
- title: self and Self
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=struct+Coordinates+%7B%0A++++x%3A+i32%2C%0A++++y%3A+i32%2C%0A%7D%0A%0Aimpl+Coordinates+%7B%0A++++%2F%2F+the+return+value%2C+Self%2C+has+the+data+type+as+the+implemented+struct+%0A++++%2F%2F+this+method+is+static%0A++++fn+new%28xval%3A+i32%2C+yval%3A+i32%29+-%3E+Self+%7B%0A++++++++return+Coordinates+%7B%0A++++++++++++x%3A+xval%2C%0A++++++++++++y%3A+yval%2C%0A++++++++%7D%0A++++%7D%0A++++%0A++++fn+setx%28%26mut+self%2C+xval%3A+i32%29+%7B%0A++++++++self.x+%3D+xval%3B%0A++++%7D%0A++++%0A++++fn+sety%28%26mut+self%2C+yval%3A+i32%29+%7B%0A++++++++self.y+%3D+yval%3B%0A++++%7D%0A++++%0A++++fn+disp%28%26self%29+%7B%0A++++++++println%21%28%22Point+located+at+%3A+%7B%7D+on+OX++%7B%7D+on+OY%22%2C%0A++++++++++++++++self.x%2C+self.y%29%3B%0A++++%7D%0A++++%0A%7D%0A%0Afn+main%28%29+%7B%0A++++let+mut+p+%3D+Coordinates%3A%3Anew%28-1i32%2C+1i32%29%3B%0A++++p.disp%28%29%3B%0A++++p.setx%2810++as+i32%29%3B%0A++++p.sety%28-10+as+i32%29%3B%0A++++p.disp%28%29%3B%0A%7D%0A
content_markdown: >
In Rust, `self` and `Self` are fundamental concepts in ownership and
borrowing system. Both of them are used in `impl` and `trait` blocks.

`self`:
- refers to an **instance of struct**
- reference to itself
- is the first parameter of the method
- methods containing the `self` parameter are called using the name of the instance, the operator `.` and the name of the method


`Self`:
- refers to **return type** of the method
- has the same data type as the `struct` that is implemented in a `impl` block
- can be used for static methods using the operator `::` (they do not depend on a instance of a struct or contain `self` as a parameter)
- title: Defining a macro
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=struct+Coordinates+%7B%0A++++x%3A+i32%2C%0A++++y%3A+i32%2C%0A%7D%0A%0Aimpl+Coordinates+%7B%0A++++%2F%2F+original+copy+constructor%2C+a+static+method%0A++++fn+new%28xval%3A+i32%2C+yval%3A+i32%29+-%3E+Self+%7B%0A++++++++Coordinates+%7B+x%3A+xval%2C+y%3A+yval+%7D%0A++++%7D%0A%7D%0A%0Aimpl+Coordinates+%7B%0A++++fn+disp%28%26self%29+%7B%0A++++++++println%21%28%22Point+located+at%3A+%7B%7D+on+OX%2C+%7B%7D+on+OY%22%2C+self.x%2C+self.y%29%3B%0A++++%7D%0A%7D%0A%0A%2F%2F+the+coord%21+macro%0Amacro_rules%21+coord+%7B%0A++++%28%24x%3Aexpr%2C+%24y%3Aexpr%29+%3D%3E+%7B%0A++++++++Coordinates%3A%3Anew%28%24x%2C+%24y%29%0A++++%7D%3B%0A%7D%0A%0Afn+main%28%29+%7B%0A++++%2F%2F+Use+the+coord%21+macro+to+create+a+new+Coordinates+instance%0A++++let+p1%3A+Coordinates+%3D+coord%21%281%2C+2%29%3B%0A%0A++++%2F%2F+Alternatively%2C+you+can+use+the+coord%21+macro+with+square+brackets%0A++++let+p2+%3D+coord%21%5B2%2C+2%5D%3B%0A++++%0A++++let+p3+%3D+Coordinates+%7B%0A++++++++x%3A+10i32%2C%0A++++++++y%3A+11+as+i32%2C%0A++++%7D%3B%0A++++%0A++++let+p4+%3D+Coordinates%3A%3Anew%28-10%2C+11%29%3B%0A%0A++++p1.disp%28%29%3B%0A++++p2.disp%28%29%3B%0A++++p3.disp%28%29%3B%0A++++p4.disp%28%29%3B%0A%7D%0A
content_markdown: >
We talked before that we can use `macros` to simplify abstractions of our code.

Let us define a `macro` that has the functionality of a copy constructor
for a struct.

Notice that we group the macro's parameters using either `()` or `[]`.

The choice between using `()` and `[]` for `macro` invocations in Rust
often depends on the expected syntax and visual aesthetics. While `()` is more commonly associated with function calls and grouping expressions, `[]` is often associated with array indexing or indexing-like operations.


- title: Encapsulation With Methods
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=struct%20SeaCreature%20%7B%0A%20%20%20%20noise%3A%20String%2C%0A%7D%0A%0Aimpl%20SeaCreature%20%7B%0A%20%20%20%20fn%20get_sound(%26self)%20-%3E%20%26str%20%7B%0A%20%20%20%20%20%20%20%20%26self.noise%0A%20%20%20%20%7D%0A%7D%0A%0Afn%20main()%20%7B%0A%20%20%20%20let%20creature%20%3D%20SeaCreature%20%7B%0A%20%20%20%20%20%20%20%20noise%3A%20String%3A%3Afrom(%22blub%22)%2C%0A%20%20%20%20%7D%3B%0A%20%20%20%20println!(%22%7B%7D%22%2C%20creature.get_sound())%3B%0A%7D%0A
Expand Down
49 changes: 49 additions & 0 deletions lessons/en/chapter_8.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,55 @@
will validate the lifetime of references doesn't last longer than what

it refers to (otherwise we'd get an error when we used it!).
- title: What is a pointer?
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&code=fn+main%28%29+%7B%0A++++let+a%3A+i32+%3D+12i32%3B%0A++++let+b%3A+%26i32+%3D+%26a%3B+++%2F%2F+pointer+to+i32%0A++++let+c%3A+%26%26i32+%3D+%26b%3B++%2F%2F+pointer+to+pointer+to+i32%0A++++let+d%3A+%26%26%26i32+%3D+%26c%3B%09%2F%2F+pointer+to+pointer+to+pointer+to+i32%0A++++%0A++++println%21%28%22%7B%7D+%7B%7D+%7B%7D+%7B%7D%22%2C+a%2C+b%2C+c%2C+d%29%3B%0A++++println%21%28%22%7B%7D+%7B%7D+%7B%7D+%7B%7D%22%2C+a%2C+*b%2C+**c%2C+***d%29%3B%0A%7D%0A
content_markdown: >
A pointer is a variable that stores a memory address.

Each variable:
- has a name
- has a data type
- has an address (in the RAM memory)
- stores an value

Why do use data types?

By using data types, we basically tell the CPU how much memory to
allocate for the variables we declare. For instance, the compiler
allocates 8 bytes for each `i8` and `u8` variable. Without pointers, a variables stores a `value`.

You've seen `u16`, `f64`, `usize`. These are data types.
So are `&i32`, `&&i32` `&&&i32` and so on.

The same logic applies to pointers. A pointer is a data type itself and
when we use pointer, the variables stores the `address` of the variable
instead of `value`. For pointer, the stored `value` is an `address`.


| variable name | data type | address | stored value |
| ------------- | --------- | ------- | --------------- |
| a | i32 | 0x100 | 12 |
| b = &a | &i32 | 0x132 | 0x100 (addr) |
| c = &b | &&i32 | 0x2a1 | 0x132 (addr) |
| d = &c | &&&i32 | 0x712 | 0x2a1 (addr) |

> The CPU chooses the address of a variable at runtime
> Do not expect to have the same address at different executions

All variables `i32`, `&i32`, `&&i32`, `&&&i32` are 32-bit variable.

`i32` -> stores a concrete value
`&...&i32` -> stores an address


However, when you try to print references (like `&i32`, `&&i32`, `&&&i32`),
Rust automatically `dereferences` them when using the `{}` format specifier in a `println!` `macro`. This means that the `values` themselves are
printed, not their `addresses`.

[![Pointer](https://i.redd.it/swszegbgpbr71.jpg)
This is for `C`.
For Rust, think that `int` is `u128`, and `*` is Rust's `&`.
- title: Raw Pointers
code: >-
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&code=fn%20main()%20%7B%0A%20%20%20%20let%20a%20%3D%2042%3B%0A%20%20%20%20let%20memory_location%20%3D%20%26a%20as%20*const%20i32%20as%20usize%3B%0A%20%20%20%20println!(%22Data%20is%20here%20%7B%7D%22%2C%20memory_location)%3B%0A%7D%0A
Expand Down
Loading