You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/en/docs/a8.primitive-data-types.md
+16-8Lines changed: 16 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -156,7 +156,15 @@ let (b, c) = a; // b = 1, c = 1.5
156
156
157
157
leta= (1, 1.5, true, 'a');
158
158
let (b, _, _, c) =a; // b = 1, c = 'a'
159
+
let (b, .., c) =a; // b = 1, c = 'a'
159
160
161
+
leta= (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
160
168
// Nesting
161
169
leta= (1, 1.5);
162
170
letb= (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
284
292
285
293
- 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.
286
294
287
-
```rust
288
-
leta=5i8; // Equals to `let a: i8 = 5;`
295
+
```rust
296
+
leta=5i8; // Equals to `let a: i8 = 5;`
289
297
290
-
letb=100_000_000; // Equals to `let b = 100000000;`
291
-
// 💡 The placements of _s are not strict. ex. 10000_0000 is also valid.
298
+
letb=100_000_000; // Equals to `let b = 100000000;`
299
+
// 💡 The placements of _s are not strict. ex. 10000_0000 is also valid.
292
300
293
-
letpi=3.141_592_653_59_f64; // Equals to `let pi: f64 = 3.14159265359`
294
-
// 💡 make sure group digits consistently by underscores avoid warnings
301
+
letpi=3.141_592_653_59_f64; // Equals to `let pi: f64 = 3.14159265359`
302
+
// 💡 make sure group digits consistently by underscores avoid warnings
295
303
296
-
constPI:f64=3.141_592_653_59; // In the constants and statics, the data type must be annotated in the beginning.
297
-
```
304
+
constPI:f64=3.141_592_653_59; // In the constants and statics, the data type must be annotated in the beginning.
Copy file name to clipboardExpand all lines: content/en/docs/b4.generics.md
+97-68Lines changed: 97 additions & 68 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,128 +3,157 @@ title: Generics
3
3
slug: generics
4
4
---
5
5
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.
7
7
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.
9
11
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.
11
19
12
20
```rust
13
-
fntakes_anything<T>(x:T) { // x has type T, T is a generic type
21
+
fnfirst<T>(x:T, _y:T) ->T { // 💡 Instead of specific type, we use T and add <T> at first
22
+
x
14
23
}
15
24
16
-
fntakes_two_of_the_same_things<T>(x:T, y:T) { // Both x and y has the same type
`{}` 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.
24
56
25
57
```rust
26
-
structPoint<T> {
27
-
x:T,
28
-
y:T,
58
+
usestd::fmt::{Debug, Display};
59
+
60
+
fnprint_together<T:Display+Debug>(x:T, y:T) {
61
+
println!("{} {:?}", x, y);
29
62
}
30
63
31
64
fnmain() {
32
-
letpoint_a=Point { x:0, y:0 }; //T is a int type
33
-
letpoint_b=Point { x:0.0, y:0.0 }; //T is a float type
// 🔎 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
+
}
38
87
```
39
88
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
41
92
42
93
```rust
43
-
enumOption<T> {
94
+
// An output can have either Some value or no value/ None.
95
+
enumOption<T> { // T is a generic and it can contain any type of value.
44
96
Some(T),
45
97
None,
46
98
}
47
99
48
-
enumResult<T, E> {
100
+
// A result can represent either success/ Ok or failure/ Err.
101
+
enumResult<T, E> { // T and E are generics. T can contain any type of value, E can be any error.
49
102
Ok(T),
50
103
Err(E),
51
104
}
52
105
```
53
106
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.
// if username can be found in the system, set userId
64
-
returnSome(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
73
112
74
-
// 02 - - - - - - - - - - - - - - - - - - - - - -
113
+
```rust
75
114
structTask {
76
115
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`.
78
117
}
118
+
```
119
+
120
+
```rust
121
+
fnget_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
+
returnSome(userId); // 💡 Instead of return userId, return Some(userId)
79
124
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
+
}
86
128
87
129
fnmain() {
88
130
letusername="anonymous";
89
-
matchget_id_by_username(username) {
131
+
matchget_id_by_username(username) {// 💡 We can use pattern matching to catch the relevant return type (Some/None)
90
132
None=>println!("User not found"),
91
-
Some(i) =>println!("User Id: {}", i)
133
+
Some(i) =>println!("User Id: {}", i),
92
134
}
93
135
}
94
136
```
95
137
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.
// if the file is not found on the system, return error
104
-
returnErr("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
+
fnget_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
+
returnErr("File can not be found!"); // 💡 Instead panic/ break when the file can not be found; return Err(something)
109
144
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
+
}
117
149
118
150
fnmain() {
119
151
letmutfile_name="file_a";
120
-
matchget_word_count_from_file(file_name) {
152
+
matchget_word_count_from_file(file_name) {// 💡 We can use pattern matching to catch the relevant return type (Ok/Err)
121
153
Ok(i) =>println!("Word Count: {}", i),
122
154
Err(e) =>println!("Error: {}", e)
123
155
}
124
156
}
125
157
```
126
158
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