Skip to content

Commit b9b05c1

Browse files
committed
Merge remote-tracking branch 'origin/main' into github-pages
2 parents d4375e7 + ce99c41 commit b9b05c1

File tree

4 files changed

+151
-97
lines changed

4 files changed

+151
-97
lines changed

content/en/docs/a8.primitive-data-types.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,15 @@ let (b, c) = a; // b = 1, c = 1.5
156156

157157
let a = (1, 1.5, true, 'a');
158158
let (b, _, _, c) = a; // b = 1, c = 'a'
159+
let (b, .., c) = a; // b = 1, c = 'a'
159160

161+
let a = (1, 2, 3, true, false, 'a', 'b', 'c');
162+
let (b, ..) = a; // b = 1
163+
let (.., c) = a; // c = 'c'
164+
let (e, f, g, .., h, i, j) = a; // 1 2 3 'a' 'b' 'c'
165+
```
166+
167+
```rust
160168
// Nesting
161169
let a = (1, 1.5);
162170
let b = (a, (2, 4), 6); // ((1, 1.5), (2, 4), 6)
@@ -284,14 +292,14 @@ We can check the default byte sizes of data types via `std::mem::size_of`. For e
284292

285293
- Other than adding the type annotations to the variables, **for numeric types**, we can append the data type directly to the value as the suffix. Also, to improve the readability of long numbers, we can use `_` as a divider.
286294

287-
```rust
288-
let a = 5i8; // Equals to `let a: i8 = 5;`
295+
```rust
296+
let a = 5i8; // Equals to `let a: i8 = 5;`
289297

290-
let b = 100_000_000; // Equals to `let b = 100000000;`
291-
// 💡 The placements of _s are not strict. ex. 10000_0000 is also valid.
298+
let b = 100_000_000; // Equals to `let b = 100000000;`
299+
// 💡 The placements of _s are not strict. ex. 10000_0000 is also valid.
292300

293-
let pi = 3.141_592_653_59_f64; // Equals to `let pi: f64 = 3.14159265359`
294-
// 💡 make sure group digits consistently by underscores avoid warnings
301+
let pi = 3.141_592_653_59_f64; // Equals to `let pi: f64 = 3.14159265359`
302+
// 💡 make sure group digits consistently by underscores avoid warnings
295303

296-
const PI: f64 = 3.141_592_653_59; // In the constants and statics, the data type must be annotated in the beginning.
297-
```
304+
const PI: f64 = 3.141_592_653_59; // In the constants and statics, the data type must be annotated in the beginning.
305+
```

content/en/docs/a9.operators.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,20 @@ println!("{} {}", a.0, a.1); // 2 Tim
152152

153153
- About **string concatenation**,
154154

155-
```rust
156-
let (s1, s2) = ("abc", "123"); // both &str
157-
// All bellow codes return abc123 (in String data type)
155+
```rust
156+
let (s1, s2) = ("abc", "123"); // both &str
157+
// All bellow codes return abc123 (in String data type)
158158

159-
// 1. via + operator
160-
let s = String::from(s1) + s2; // String + &str
159+
// 1. via + operator
160+
let s = String::from(s1) + s2; // String + &str
161161

162-
// 2. via push_str method
163-
let mut s = String::from(s1);
164-
s.push_str(s2); // String + &str
162+
// 2. via push_str method
163+
let mut s = String::from(s1);
164+
s.push_str(s2); // String + &str
165165

166-
// 3. via format! macro
167-
let s = format!("{s1}{s2}"); // &str/String + &str/String
166+
// 3. via format! macro
167+
let s = format!("{s1}{s2}"); // &str/String + &str/String
168168

169-
// 4. via concat method
170-
let s = [s1, s2].concat(); // &str or String array
171-
```
169+
// 4. via concat method
170+
let s = [s1, s2].concat(); // &str or String array
171+
```

content/en/docs/b3.enums.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ slug: enums
1010
- Unnamed ordered data (a tuple variant)
1111
- Named data (a struct variant)
1212

13-
> 💡In other words, any type of valid struct (unit, tuple, c-like) can be used as an enum variant.
14-
1513
## Definition
1614

1715
### With Unit Variants
@@ -34,15 +32,17 @@ enum Day {
3432
```rust
3533
enum FlashMessage {
3634
Success, // 💡 A unit variant (no data)
37-
Error(u8, String), // 💡 A tuple variant (One/more , separated data)
38-
Warning { field: String, message: String }, // 💡 A struct variant (One/more , separated name: value data)
35+
Error(u8, String), // 💡 A tuple variant (one or more , separated data)
36+
Warning { field: String, message: String }, // 💡 A struct variant (one or more , separated name: value data)
3937
}
4038
```
4139

4240
## Initialization
4341

42+
### With Different Kinds of Variants
43+
4444
```rust
45-
#[allow(dead_code)] // 💡 Remove dead_code warnings, as we don't access the elements of variants.
45+
#![allow(dead_code)] // 💡 Remove dead_code warnings, as we don't access the elements of variants.
4646

4747
#[derive(Debug)]
4848
enum FlashMessage {
@@ -67,6 +67,25 @@ fn main() {
6767
}
6868
```
6969

70+
### With a Default Variant
71+
72+
```rust
73+
#[derive(Default)]
74+
enum Hand {
75+
Left,
76+
#[default] // 💡Set Right as the default variant
77+
Right,
78+
},
79+
80+
fn main() {
81+
let a = Hand::default(); // Initialization with the default variant
82+
83+
assert_eq!(a, Hand::Right); // Hand default value is Right
84+
}
85+
86+
// 💡 #[derive(Default)] attribute automatically generates a default implementation for the Default trait for a struct or enum.
87+
```
88+
7089
## Pattern Matching & Destructuring
7190

7291
### By `match`
@@ -97,9 +116,8 @@ fn main() {
97116
```
98117

99118
```rust
100-
#[allow(dead_code)] // 💡 Remove dead_code warnings, as we don't access all elements of the variants.
119+
#![allow(dead_code)] // 💡 Remove dead_code warnings, as we don't access all elements of the variants.
101120

102-
#[derive(Debug)]
103121
enum FlashMessage {
104122
Success,
105123
Error(u32, String),
@@ -124,7 +142,6 @@ fn main() {
124142
```rust
125143
#![allow(dead_code)] // 💡 Remove dead_code warnings, as we don't access the all elements of variants.
126144

127-
#[derive(Debug)]
128145
enum FlashMessage {
129146
Success,
130147
Error(u32, String),

content/en/docs/b4.generics.md

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -3,128 +3,157 @@ title: Generics
33
slug: generics
44
---
55

6-
> [📖](https://doc.rust-lang.org/beta/book/first-edition/generics.html) Sometimes, when writing a function or data type, we may want it to work for multiple types of arguments. In Rust, we can do this with generics.
6+
The core concept of Rust generics is abstraction over types. In other words, we can write code that can operate on any data type without specifying the exact type but uppercase letter (or [PascalCase](https://en.wikipedia.org/wiki/Camel_case) identifier). In the compile time Rust ensures the type safety and generates optimized code for each concrete type used in the code.
77

8-
💭 The concept is, instead of declaring a specific data type we use an uppercase letter(or [PascalCase](https://en.wikipedia.org/wiki/Camel_case) identifier). ex, **instead of x : u8** we use **x : T** . but we have to inform to the compiler that T is a generic type(can be any type) by adding `<T>` at first.
8+
For example,
9+
- Instead of `x: u8` we use **`x: T`**.
10+
- And inform the compiler that `T` is a generic type (can be any type) by adding **`<T>`** at first.
911

10-
## Generalizing functions
12+
> 💡 Using T, U, V ... as generic type names is quite a convention. We can use any PascalCase names as well.
13+
14+
## Functions
15+
16+
### With One Generic Type
17+
18+
💡 For simplicity, `fn first` accepts two arguments of the same type `T` and returns the first argument. As we don't use the second argument in the function, we prefix it with `_`, to prevent `unused_variables` warning.
1119

1220
```rust
13-
fn takes_anything<T>(x: T) { // x has type T, T is a generic type
21+
fn first<T>(x: T, _y: T) -> T { // 💡 Instead of specific type, we use T and add <T> at first
22+
x
1423
}
1524

16-
fn takes_two_of_the_same_things<T>(x: T, y: T) { // Both x and y has the same type
25+
fn main() {
26+
let a: i8 = first(0, -1);
27+
let b: i32 = first(1, 2);
28+
let c: bool = first(true, false);
29+
let d: String = first("01".to_string(), "02".to_string());
30+
31+
println!("{a} {b} {c} {d}"); // 0 1 true 01
1732
}
33+
```
34+
35+
### With Multiple Generic Types
36+
37+
```rust
38+
fn first<T, U>(x: T, _y: U) -> T {
39+
x
40+
}
41+
42+
fn main() {
43+
let a: i8 = first(0i8, -1i32); // x: i8, y: i32
44+
let b: i32 = first(1i32, 2i64); // x: i32, y: i64
45+
46+
let c: bool = first(true, false); // x: bool, y: bool
47+
// ⭐️ Even funtions with multiple generic types, we can have same type.
1848

19-
fn takes_two_things<T, U>(x: T, y: U) { // Multiple types
49+
println!("{a} {b} {c}"); // 0 1 true
2050
}
2151
```
2252

23-
## Generalizing structs
53+
### With Trait Bounds
54+
55+
`{}` requires the `std::fmt::Display` trait and `{:?}` requires the `std::fmt::Debug` trait. We have to set `T: Display` or `T: Debug` or both `T: Display + Debug` to tell the compiler that `T` satisfy the requirements for either operation.
2456

2557
```rust
26-
struct Point<T> {
27-
x: T,
28-
y: T,
58+
use std::fmt::{Debug, Display};
59+
60+
fn print_together<T: Display + Debug>(x: T, y: T) {
61+
println!("{} {:?}", x, y);
2962
}
3063

3164
fn main() {
32-
let point_a = Point { x: 0, y: 0 }; // T is a int type
33-
let point_b = Point { x: 0.0, y: 0.0 }; // T is a float type
65+
print_together(0, 1); // 0 1
66+
print_together("001", "002"); // 001 "002"
3467
}
68+
```
69+
70+
## With Structs
71+
72+
```rust
73+
use std::fmt::Display;
74+
75+
struct Point<T: Display> {
76+
x: T,
77+
y: T,
78+
}
79+
80+
fn main() {
81+
let a = Point { x: 0_i8, y: 1 }; // x, y: i8
82+
let b = Point { x: 0.0001_f64, y: 0.0002 }; // x, y: f64
3583

36-
// 🔎 When adding an implementation for a generic struct, the type parameters should be declared after the impl as well
37-
// impl<T> Point<T> {
84+
println!("{} {}", a.x, a.y); // 0 1
85+
println!("{} {}", b.x, b.y); // 0.0001 0.0002
86+
}
3887
```
3988

40-
## Generalizing enums
89+
💯 When adding an implementation for a generic struct, the type parameters should be declared after the impl as well. Ex, `impl<T> Point<T>`
90+
91+
## With Enums
4192

4293
```rust
43-
enum Option<T> {
94+
// An output can have either Some value or no value/ None.
95+
enum Option<T> { // T is a generic and it can contain any type of value.
4496
Some(T),
4597
None,
4698
}
4799

48-
enum Result<T, E> {
100+
// A result can represent either success/ Ok or failure/ Err.
101+
enum Result<T, E> { // T and E are generics. T can contain any type of value, E can be any error.
49102
Ok(T),
50103
Err(E),
51104
}
52105
```
53106

54-
> ⭐️ Above [Option](https://doc.rust-lang.org/std/option/index.html) and [Result](https://doc.rust-lang.org/std/result/index.html) types are kind of special generic types which are already defined in Rust’s standard library. 
55-
> - An **optional value** can have either **Some** value or no value/ **None**.
56-
> - A **result** can represent either success/ **Ok** or failure/ **Err**
107+
⭐️ [Option](https://doc.rust-lang.org/std/option/index.html) and [Result](https://doc.rust-lang.org/std/result/index.html) types are kind of special generic types which are already defined in Rust’s standard library.
108+
- An **optional value** can have either **Some** value or no value/ **None**. Express the possibility of absence.
109+
- A **result** can represent either success/ **Ok** or failure/ **Err**. Expresses the possibility of failure.
57110

58-
### Usages of Option
59-
60-
```rust
61-
// 01 - - - - - - - - - - - - - - - - - - - - - -
62-
fn get_id_by_username(username: &str) -> Option<usize> {
63-
// if username can be found in the system, set userId
64-
return Some(userId);
65-
// else
66-
None
67-
}
68-
69-
// 💭 So, on the above function, instead of setting return type as usize
70-
// set return type as Option<usize>
71-
// Instead of return userId, return Some(userId)
72-
// else None (💡remember? last return statement no need return keyword and ending ;)
111+
### Option
73112

74-
// 02 - - - - - - - - - - - - - - - - - - - - - -
113+
```rust
75114
struct Task {
76115
title: String,
77-
assignee: Option<Person>,
116+
assignee: Option<Person>, // 💡 Instead of `assignee: Person`, we use `assignee: Option<Person>` as the assignee can be `None`.
78117
}
118+
```
119+
120+
```rust
121+
fn get_id_by_username(username: &str) -> Option<usize> { // 💡 Instead of setting return type as `usize`, set it `Option<usize>`
122+
// if username can be found in the system, return userId
123+
return Some(userId); // 💡 Instead of return userId, return Some(userId)
79124

80-
// 💭 Instead of assignee: Person, we use Option<Person>
81-
// because the task has not been assigned to a specific person
82-
83-
// - - - - - - - - - - - - - - - - - - - - - - -
84-
// When using Option types as return types on functions
85-
// we can use pattern matching to catch the relevant return type(Some/None) when calling them
125+
// else
126+
None // 💡 The last return statement no need `return` keyword and ending `;`
127+
}
86128

87129
fn main() {
88130
let username = "anonymous";
89-
match get_id_by_username(username) {
131+
match get_id_by_username(username) { // 💡 We can use pattern matching to catch the relevant return type (Some/None)
90132
None => println!("User not found"),
91-
Some(i) => println!("User Id: {}", i)
133+
Some(i) => println!("User Id: {}", i),
92134
}
93135
}
94136
```
95137

96-
### Usages of Result
97-
98-
> [📖](https://doc.rust-lang.org/book/first-edition/error-handling.html) The Option type is a way to use Rust’s type system to express the possibility of absence. Result expresses the possibility of error.
138+
### Result
99139

100140
```rust
101-
// - - - - - - - - - - - - - - - - - - - - - -
102-
fn get_word_count_from_file(file_name: &str) -> Result<u32, &str> {
103-
// if the file is not found on the system, return error
104-
return Err("File can not be found!")
105-
// else, count and return the word count
106-
// let mut word_count: u32; ....
107-
Ok(word_count)
108-
}
141+
fn get_word_count_from_file(file_name: &str) -> Result<u32, &str> { // 💡 Instead of setting return type as `u32`, set it `Result<u32, &str>`
142+
// if the file is not found on the system, return error
143+
return Err("File can not be found!"); // 💡 Instead panic/ break when the file can not be found; return Err(something)
109144

110-
// 💭 On the above function,
111-
// instead panic(break) the app, when the file can not be found; return Err(something)
112-
// or when it could get the relevant data; return Ok(data)
113-
114-
115-
// - - - - - - - - - - - - - - - - - - - - - - -
116-
// We can use pattern matching to catch the relevant return type(Ok/Err) when calling it
145+
// else, count and return the word count
146+
Ok(word_count) // 💡 Instead of return `word_count`, return `Ok(word_count)`
147+
// 💡 The last return statement no need `return` keyword and ending `;`
148+
}
117149

118150
fn main() {
119151
let mut file_name = "file_a";
120-
match get_word_count_from_file(file_name) {
152+
match get_word_count_from_file(file_name) { // 💡 We can use pattern matching to catch the relevant return type (Ok/Err)
121153
Ok(i) => println!("Word Count: {}", i),
122154
Err(e) => println!("Error: {}", e)
123155
}
124156
}
125157
```
126158

127-
128-
> 🔎 Many useful methods have been implemented around Option and Result types. More information can be found on [std::option::Option](https://doc.rust-lang.org/std/option/enum.Option.html) and [std::result::Result](https://doc.rust-lang.org/std/result/enum.Result.html) pages on Rust doc.
129-
130-
⭐️ Also **more practical examples** of options & results can be found on [Error Handling](https://doc.rust-lang.org/book/first-edition/error-handling.html) section in Rust doc.
159+
💭 This is a quick reference about the `Option` and `Result` as enums. Please don’t worry about them much now, as we will discuss them later.

0 commit comments

Comments
 (0)