update repo layout

This commit is contained in:
sunface
2022-03-23 20:04:00 +08:00
parent e2d3027b60
commit c1d8b06518
111 changed files with 958 additions and 4 deletions

1
en/src/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
book

94
en/src/SUMMARY.md Normal file
View File

@ -0,0 +1,94 @@
# Summary
- [Rust By Practice](why-exercise.md)
- [Small projects with Elegant code](elegant-code-base.md)
- [Variables](variables.md)
- [Basic Types](basic-types/intro.md)
- [Numbers](basic-types/numbers.md)
- [Char, Bool and Unit](basic-types/char-bool-unit.md)
- [Statements and Expressions](basic-types/statements-expressions.md)
- [Functions](basic-types/functions.md)
- [Ownership and Borrowing](ownership/intro.md)
- [Ownership](ownership/ownership.md)
- [Reference and Borrowing](ownership/borrowing.md)
- [Compound Types](compound-types/intro.md)
- [string](compound-types/string.md)
- [Array](compound-types/array.md)
- [Slice](compound-types/slice.md)
- [Tuple](compound-types/tuple.md)
- [Struct](compound-types/struct.md)
- [Enum](compound-types/enum.md)
- [Flow Control](flow-control.md)
- [Pattern Match](pattern-match/intro.md)
- [match, matches! and if let](pattern-match/match-iflet.md)
- [Patterns](pattern-match/patterns.md)
- [Method & Associated function](method.md)
- [Generics and Traits](generics-traits/intro.md)
- [Generics](generics-traits/generics.md)
- [Const Generics](generics-traits/const-generics.md)
- [Traits](generics-traits/traits.md)
- [Trait Object](generics-traits/trait-object.md)
- [Advanced Traits](generics-traits/advanced-traits.md)
- [Collection Types](collections/intro.md)
- [String](collections/string.md)
- [Vector](collections/vector.md)
- [HashMap](collections/hashmap.md)
- [Type Conversion](type-conversions/intro.md)
- [as](type-conversions/as.md)
- [From/Into](type-conversions/from-into.md)
- [Others](type-conversions/others.md)
- [Result and panic](result-panic/intro.md)
- [panic!](result-panic/panic.md)
- [Result and ?](result-panic/result.md)
- [Crate and Module](crate-module/intro.md)
- [Package and Crate](crate-module/crate.md)
- [Module](crate-module/module.md)
- [Advanced use and pub](crate-module/use-pub.md)
- [Comments and Docs](comments-docs.md)
- [Formatted output](formatted-output/intro.md)
- [println! and format!](formatted-output/println.md)
- [Debug and Display](formatted-output/debug-display.md)
- [formating](formatted-output/formatting.md)
- [Lifetime](lifetime/intro.md)
- [basic](lifetime/basic.md)
- [&'static and T: 'static TODO](lifetime/static.md)
- [advance TODO](lifetime/advance.md)
- [Functional programing TODO](functional-programing/intro.md)
- [Closure](functional-programing/cloure.md)
- [Iterator](functional-programing/iterator.md)
- [newtype and Sized TODO](newtype-sized.md)
- [Smart pointers TODO](smart-pointers/intro.md)
- [Box](smart-pointers/box.md)
- [Deref](smart-pointers/deref.md)
- [Drop](smart-pointers/drop.md)
- [Rc and Arc](smart-pointers/rc-arc.md)
- [Cell and RefCell](smart-pointers/cell-refcell.md)
- [Weak and Circle reference TODO](weak.md)
- [Self referential TODO](self-referential.md)
- [Threads TODO](threads/intro.md)
- [Basic using](threads/basic-using.md)
- [Message passing](threads/message-passing.md)
- [Sync](threads/sync.md)
- [Atomic](threads/atomic.md)
- [Send and Sync](threads/send-sync.md)
- [Global variables TODO](global-variables.md)
- [Errors TODO](errors.md)
- [Unsafe doing](unsafe/intro.md)
- [Inline assembly](unsafe/inline-asm.md)
- [Macro TODO](macro.md)
- [Tests TODO](tests/intro.md)
- [Write Tests](tests/write-tests.md)
- [Benchmark](tests/benchmark.md)
- [Unit and Integration](tests/unit-integration.md)
- [Assertions](tests/assertions.md)
- [Async/Await TODO](async/intro.md)
- [async and await!](async/async-await.md)
- [Future](async/future.md)
- [Pin and Unpin](async/pin-unpin.md)
- [Stream](async/stream.md)
- [Standard Library TODO](std/intro.md)
- [String](std/String.md)
- [Fighting with Compiler](fight-compiler/intro.md)
- [Borrowing](fight-compiler/borrowing.md)

1
en/src/about.md Normal file
View File

@ -0,0 +1 @@
# Rust By Practice

View File

@ -0,0 +1 @@
# async and await!

1
en/src/async/future.md Normal file
View File

@ -0,0 +1 @@
# Future

1
en/src/async/intro.md Normal file
View File

@ -0,0 +1 @@
# Async/Await

View File

@ -0,0 +1 @@
# Pin and Unpin

1
en/src/async/stream.md Normal file
View File

@ -0,0 +1 @@
# Stream

View File

@ -0,0 +1,100 @@
# Char, Bool and Unit
### Char
1. 🌟
```rust, editable
// make it work
use std::mem::size_of_val;
fn main() {
let c1 = 'a';
assert_eq!(size_of_val(&c1),1);
let c2 = '中';
assert_eq!(size_of_val(&c2),3);
println!("Success!")
}
```
2. 🌟
```rust, editable
// make it work
fn main() {
let c1 = "中";
print_char(c1);
}
fn print_char(c : char) {
println!("{}", c);
}
```
### Bool
3. 🌟
```rust, editable
// make println! work
fn main() {
let _f: bool = false;
let t = true;
if !t {
println!("Success!")
}
}
```
4. 🌟
```rust, editable
// make it work
fn main() {
let f = true;
let t = true && false;
assert_eq!(t, f);
println!("Success!")
}
```
### Unit type
5. 🌟🌟
```rust,editable
// make it work, don't modify `implicitly_ret_unit` !
fn main() {
let _v: () = ();
let v = (2, 3);
assert_eq!(v, implicitly_ret_unit());
println!("Success!")
}
fn implicitly_ret_unit() {
println!("I will return a ()")
}
// don't use this one
fn explicitly_ret_unit() -> () {
println!("I will return a ()")
}
```
6. 🌟🌟 what's the size of the unit type?
```rust,editable
// modify `4` in assert to make it work
use std::mem::size_of_val;
fn main() {
let unit: () = ();
assert!(size_of_val(&unit) == 4);
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,101 @@
# Functions
1. 🌟🌟🌟
```rust,editable
fn main() {
// don't modify the following two lines!
let (x, y) = (1, 2);
let s = sum(x, y);
assert_eq!(s, 3);
println!("Success!")
}
fn sum(x, y: i32) {
x + y;
}
```
2. 🌟
```rust,editable
fn main() {
print();
}
// replace i32 with another type
fn print() -> i32 {
println!("Success!")
}
```
3. 🌟🌟🌟
```rust,editable
// solve it in two ways
// DON'T let `println!` works
fn main() {
never_return();
println!("Failed!")
}
fn never_return() -> ! {
// implement this function, don't modify the fn signatures
}
```
### Diverging functions
Diverging functions never return to the caller, so they may be used in places where a value of any type is expected.
4. 🌟🌟
```rust,editable
fn main() {
println!("Success!");
}
fn get_option(tp: u8) -> Option<i32> {
match tp {
1 => {
// TODO
}
_ => {
// TODO
}
};
// Rather than returning a None, we use a diverging function instead
never_return_fn()
}
// IMPLEMENT this function in THREE ways
fn never_return_fn() -> ! {
}
```
5. 🌟🌟
```rust,editable
fn main() {
// FILL in the blank
let b = __;
let v = match b {
true => 1,
// Diverging functions can also be used in match expression to replace a value of any value
false => {
println!("Success!");
panic!("we have no value for `false`, but we can panic")
}
};
println!("Excercise Failed if printing out this line!");
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,5 @@
# Basic Types
Learning resources:
- English: [Rust Book 3.2 and 3.3](https://doc.rust-lang.org/book/ch03-02-data-types.html)
- 简体中文: [Rust语言圣经 - 基本类型](https://course.rs/basic/base-type/index.html)

View File

@ -0,0 +1,181 @@
# Numbers
### Integer
1. 🌟
> Tips: If we don't explicitly give one type to a varible, then the compiler will infer one for us
```rust,editable
// remove something to make it work
fn main() {
let x: i32 = 5;
let mut y: u32 = 5;
y = x;
let z = 10; // type of z ?
println!("Success!")
}
```
2. 🌟
```rust,editable
// fill the blank
fn main() {
let v: u16 = 38_u8 as __;
println!("Success!")
}
```
3. 🌟🌟🌟
> Tips: If we don't explicitly give one type to a varible, then the compiler will infer one for us
```rust,editable
// modify `assert_eq!` to make it work
fn main() {
let x = 5;
assert_eq!("u32".to_string(), type_of(&x));
println!("Success!")
}
// get the type of given variable, return a string representation of the type , e.g "i8", "u8", "i32", "u32"
fn type_of<T>(_: &T) -> String {
format!("{}", std::any::type_name::<T>())
}
```
4. 🌟🌟
```rust,editable
// fill the blanks to make it work
fn main() {
assert_eq!(i8::MAX, __);
assert_eq!(u8::MAX, __);
println!("Success!")
}
```
5. 🌟🌟
```rust,editable
// fix errors and panics to make it work
fn main() {
let v1 = 251_u8 + 8;
let v2 = i8::checked_add(251, 8).unwrap();
println!("{},{}",v1,v2);
}
```
6. 🌟🌟
```rust,editable
// modify `assert!` to make it work
fn main() {
let v = 1_024 + 0xff + 0o77 + 0b1111_1111;
assert!(v == 1579);
println!("Success!")
}
```
### Floating-Point
7. 🌟
```rust,editable
// replace ? with your answer
fn main() {
let x = 1_000.000_1; // ?
let y: f32 = 0.12; // f32
let z = 0.01_f64; // f64
println!("Success!")
}
```
1. 🌟🌟 make it work in two distinct ways
```rust,editable
fn main() {
assert!(0.1+0.2==0.3);
println!("Success!")
}
```
### Range
9. 🌟🌟 two goals: 1. modify `assert!` to make it work 2. make `println!` output: 97 - 122
```rust,editable
fn main() {
let mut sum = 0;
for i in -3..2 {
sum += i
}
assert!(sum == -3);
for c in 'a'..='z' {
println!("{}",c);
}
}
```
10. 🌟🌟
```rust,editable
// fill the blanks
use std::ops::{Range, RangeInclusive};
fn main() {
assert_eq!((1..__), Range{ start: 1, end: 5 });
assert_eq!((1..__), RangeInclusive::new(1, 5));
println!("Success!")
}
```
### Computations
11. 🌟
```rust,editable
// fill the blanks and fix the errors
fn main() {
// Integer addition
assert!(1u32 + 2 == __);
// Integer subtraction
assert!(1i32 - 2 == __);
assert!(1u8 - 2 == -1);
assert!(3 * 50 == __);
assert!(9.6 / 3.2 == 3.0); // error ! make it work
assert!(24 % 5 == __);
// Short-circuiting boolean logic
assert!(true && false == __);
assert!(true || false == __);
assert!(!true == __);
// Bitwise operations
println!("0011 AND 0101 is {:04b}", 0b0011u32 & 0b0101);
println!("0011 OR 0101 is {:04b}", 0b0011u32 | 0b0101);
println!("0011 XOR 0101 is {:04b}", 0b0011u32 ^ 0b0101);
println!("1 << 5 is {}", 1u32 << 5);
println!("0x80 >> 2 is 0x{:x}", 0x80u32 >> 2);
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,70 @@
# Statements and Expressions
### Examples
```rust,editable
fn main() {
let x = 5u32;
let y = {
let x_squared = x * x;
let x_cube = x_squared * x;
// This expression will be assigned to `y`
x_cube + x_squared + x
};
let z = {
// The semicolon suppresses this expression and `()` is assigned to `z`
2 * x;
};
println!("x is {:?}", x);
println!("y is {:?}", y);
println!("z is {:?}", z);
}
```
### Exercises
1. 🌟🌟
```rust,editable
// make it work with two ways
fn main() {
let v = {
let mut x = 1;
x += 2
};
assert_eq!(v, 3);
println!("Success!")
}
```
2. 🌟
```rust,editable
fn main() {
let v = (let x = 3);
assert!(v == 3);
println!("Success!")
}
```
3. 🌟
```rust,editable
fn main() {
let s = sum(1 , 2);
assert_eq!(s, 3);
println!("Success!")
}
fn sum(x: i32, y: i32) -> i32 {
x + y;
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1 @@
# Circle reference and Self referential

View File

@ -0,0 +1,223 @@
# HashMap
Where vectors store values by an integer index, HashMaps store values by key. It is a hash map implemented with quadratic probing and SIMD lookup. By default, `HashMap` uses a hashing algorithm selected to provide resistance against HashDoS attacks.
The default hashing algorithm is currently `SipHash 1-3`, though this is subject to change at any point in the future. While its performance is very competitive for medium sized keys, other hashing algorithms will outperform it for small keys such as integers as well as large keys such as long strings, though those algorithms will typically not protect against attacks such as HashDoS.
The hash table implementation is a Rust port of Googles [SwissTable](https://abseil.io/blog/20180927-swisstables). The original C++ version of SwissTable can be found [here](https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h), and this [CppCon talk](https://www.youtube.com/watch?v=ncHmEUmJZf4) gives an overview of how the algorithm works.
### Basic Operations
1. 🌟🌟
```rust,editbale
// FILL in the blanks and FIX the erros
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert("Sunface", 98);
scores.insert("Daniel", 95);
scores.insert("Ashley", 69.0);
scores.insert("Katie", "58");
// get returns a Option<&V>
let score = scores.get("Sunface");
assert_eq!(score, Some(98));
if scores.contains_key("Daniel") {
// indexing return a value V
let score = scores["Daniel"];
assert_eq!(score, __);
scores.remove("Daniel");
}
assert_eq!(scores.len(), __);
for (name, score) in scores {
println!("The score of {} is {}", name, score)
}
}
```
2. 🌟🌟
```rust,editable
use std::collections::HashMap;
fn main() {
let teams = [
("Chinese Team", 100),
("American Team", 10),
("France Team", 50),
];
let mut teams_map1 = HashMap::new();
for team in &teams {
teams_map1.insert(team.0, team.1);
}
// IMPLEMENT team_map2 in two ways
// tips: one of the approaches is to use `collect` method
let teams_map2...
assert_eq!(teams_map1, teams_map2);
println!("Success!")
}
```
3. 🌟🌟
```rust,editable
// FILL in the blanks
use std::collections::HashMap;
fn main() {
// type inference lets us omit an explicit type signature (which
// would be `HashMap<&str, u8>` in this example).
let mut player_stats = HashMap::new();
// insert a key only if it doesn't already exist
player_stats.entry("health").or_insert(100);
assert_eq!(player_stats["health"], __);
// insert a key using a function that provides a new value only if it
// doesn't already exist
player_stats.entry("health").or_insert_with(random_stat_buff);
assert_eq!(player_stats["health"], __);
// Ensures a value is in the entry by inserting the default if empty, and returns
// a mutable reference to the value in the entry.
let health = player_stats.entry("health").or_insert(50);
assert_eq!(health, __);
*health -= 50;
assert_eq!(*health, __);
println!("Success!")
}
fn random_stat_buff() -> u8 {
// could actually return some random value here - let's just return
// some fixed value for now
42
}
```
### Requirements of HashMap key
Any type that implements the `Eq` and `Hash` traits can be a key in `HashMap`. This includes:
- `bool` (though not very useful since there is only two possible keys)
- `int`, `uint`, and all variations thereof
- `String` and `&str` (tips: you can have a `HashMap` keyed by `String` and call `.get()` with an `&str`)
Note that `f32` and `f64` do not implement `Hash`, likely because [floating-point precision](https://en.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems) errors would make using them as hashmap keys horribly error-prone.
All collection classes implement `Eq` and `Hash` if their contained type also respectively implements `Eq` and `Hash`. For example, `Vec<T>` will implement `Hash` if `T`implements `Hash`.
4. 🌟🌟
```rust,editable
// FIX the errors
// Tips: `derive` is usually a good way to implement some common used traits
use std::collections::HashMap;
struct Viking {
name: String,
country: String,
}
impl Viking {
/// Creates a new Viking.
fn new(name: &str, country: &str) -> Viking {
Viking {
name: name.to_string(),
country: country.to_string(),
}
}
}
fn main() {
// Use a HashMap to store the vikings' health points.
let vikings = HashMap::from([
(Viking::new("Einar", "Norway"), 25),
(Viking::new("Olaf", "Denmark"), 24),
(Viking::new("Harald", "Iceland"), 12),
]);
// Use derived implementation to print the status of the vikings.
for (viking, health) in &vikings {
println!("{:?} has {} hp", viking, health);
}
}
```
### Capacity
Like vectors, HashMaps are growable, but HashMaps can also shrink themselves when they have excess space. You can create a `HashMap` with a certain starting capacity using `HashMap::with_capacity(uint)`, or use `HashMap::new()` to get a HashMap with a default initial capacity (recommended).
#### Example
```rust,editable
use std::collections::HashMap;
fn main() {
let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
map.insert(1, 2);
map.insert(3, 4);
// indeed ,the capacity of HashMap is not 100, so we can't compare the equality here.
assert!(map.capacity() >= 100);
// Shrinks the capacity of the map with a lower limit. It will drop
// down no lower than the supplied limit while maintaining the internal rules
// and possibly leaving some space in accordance with the resize policy.
map.shrink_to(50);
assert!(map.capacity() >= 50);
// Shrinks the capacity of the map as much as possible. It will drop
// down as much as possible while maintaining the internal rules
// and possibly leaving some space in accordance with the resize policy.
map.shrink_to_fit();
assert!(map.capacity() >= 2);
println!("Success!")
}
```
### Ownership
For types that implement the `Copy` trait, like `i32` , the values are copied into `HashMap`. For owned values like `String`, the values will be moved and `HashMap` will be the owner of those values.
5. 🌟🌟
```rust,editable
// FIX the errors with least changes
// DON'T remove any code line
use std::collections::HashMap;
fn main() {
let v1 = 10;
let mut m1 = HashMap::new();
m1.insert(v1, v1);
println!("v1 is still usable after inserting to hashmap : {}", v1);
let v2 = "hello".to_string();
let mut m2 = HashMap::new();
// ownership moved here
m2.insert(v2, v1);
assert_eq!(v2, "hello");
println!("Success!")
}
```
### Third-party Hash libs
If the performance of `SipHash 1-3` doesn't meet your requirements, you can find replacements in crates.io or github.com.
The usage of third-party hash looks like this:
```rust
use std::hash::BuildHasherDefault;
use std::collections::HashMap;
// introduce a third party hash function
use twox_hash::XxHash64;
let mut hash: HashMap<_, _, BuildHasherDefault<XxHash64>> = Default::default();
hash.insert(42, "the answer");
assert_eq!(hash.get(&42), Some(&"the answer"));
```

View File

@ -0,0 +1,6 @@
# Collection Types
Learning resources:
- English: [Rust Book Chapter 8](https://doc.rust-lang.org/book/ch08-00-common-collections.html)
- 简体中文: [Rust语言圣经 - 集合类型](https://course.rs/basic/collections/intro.html)

View File

@ -0,0 +1,206 @@
# String
`std::string::String` is a UTF-8 encoded, growable string. It is the most common string type we used in daily dev, it also has ownership over the string contents.
### Basic operations
1. 🌟🌟
```rust,editable
// FILL in the blanks and FIX errors
// 1. Don't use `to_string()`
// 2. Dont't add/remove any code line
fn main() {
let mut s: String = "hello, ";
s.push_str("world".to_string());
s.push(__);
move_ownership(s);
assert_eq!(s, "hello, world!");
println!("Success!")
}
fn move_ownership(s: String) {
println!("ownership of \"{}\" is moved here!", s)
}
```
### String and &str
A `String` is stored as a vector of bytes (`Vec<u8>`), but guaranteed to always be a valid UTF-8 sequence. `String` is heap allocated, growable and not null terminated.
`&str` is a slice (`&[u8]`) that always points to a valid UTF-8 sequence, and can be used to view into a String, just like `&[T]` is a view into `Vec<T>`.
2. 🌟🌟
```rust,editable
// FILL in the blanks
fn main() {
let mut s = String::from("hello, world");
let slice1: &str = __; // in two ways
assert_eq!(slice1, "hello, world");
let slice2 = __;
assert_eq!(slice2, "hello");
let slice3: __ = __;
slice3.push('!');
assert_eq!(slice3, "hello, world!");
println!("Success!")
}
```
3. 🌟🌟
```rust,editable
// Question: how many heap allocations are happend here ?
// Your answer:
fn main() {
// Create a String type based on `&str`
// the type of string literals is `&str`
let s: String = String::from("hello, world!");
// create a slice point to String `s`
let slice: &str = &s;
// create a String type based on the recently created slice
let s: String = slice.to_string();
assert_eq!(s, "hello, world!");
println!("Success!")
}
```
### UTF-8 & Indexing
Strings are always valid UTF-8. This has a few implications:
- the first of which is that if you need a non-UTF-8 string, consider [OsString](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html). It is similar, but without the UTF-8 constraint.
- The second implication is that you cannot index into a String
Indexing is intended to be a constant-time operation, but UTF-8 encoding does not allow us to do this. Furthermore, its not clear what sort of thing the index should return: a byte, a codepoint, or a grapheme cluster. The bytes and chars methods return iterators over the first two, respectively.
4. 🌟🌟🌟 You can't use index to access a char in a string, but you can use slice `&s1[start..end]`.
```rust,editable
// FILL in the blank and FIX errors
fn main() {
let s = String::from("hello, 世界");
let slice1 = s[0]; //tips: `h` only takes 1 byte in UTF8 format
assert_eq!(slice1, "h");
let slice2 = &s[3..5];// tips: `` takes 3 bytes in UTF8 format
assert_eq!(slice2, "世");
// iterate all chars in s
for (i, c) in s.__ {
if i == 7 {
assert_eq!(c, '世')
}
}
println!("Success!")
}
```
#### utf8_slice
You can use [utf8_slice](https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.html) to slice UTF8 string, it can index chars instead of bytes.
**Example**
```rust
use utf8_slice;
fn main() {
let s = "The 🚀 goes to the 🌑!";
let rocket = utf8_slice::slice(s, 4, 5);
// Will equal "🚀"
}
```
5. 🌟🌟🌟
> Tips: maybe you need `from_utf8` method
```rust,editable
// FILL in the blanks
fn main() {
let mut s = String::new();
__;
// some bytes, in a vector
let v = vec![104, 101, 108, 108, 111];
// Turn a bytes vector into a String
let s1 = __;
assert_eq!(s, s1);
println!("Success!")
}
```
### Representation
A String is made up of three components: a pointer to some bytes, a length, and a capacity.
The pointer points to an internal buffer String uses to store its data. The length is the number of bytes currently stored in the buffer( always stored on the heap ), and the capacity is the size of the buffer in bytes. As such, the length will always be less than or equal to the capacity.
6. 🌟🌟 If a String has enough capacity, adding elements to it will not re-allocate
```rust,editable
// modify the code below to print out:
// 25
// 25
// 25
// Here, theres no need to allocate more memory inside the loop.
fn main() {
let mut s = String::new();
println!("{}", s.capacity());
for _ in 0..2 {
s.push_str("hello");
println!("{}", s.capacity());
}
println!("Success!")
}
```
7. 🌟🌟🌟
```rust,editable
// FILL in the blanks
use std::mem;
fn main() {
let story = String::from("Rust By Practice");
// Prevent automatically dropping the String's data
let mut story = mem::ManuallyDrop::new(story);
let ptr = story.__();
let len = story.__();
let capacity = story.__();
assert_eq!(16, len);
// We can re-build a String out of ptr, len, and capacity. This is all
// unsafe because we are responsible for making sure the components are
// valid:
let s = unsafe { String::from_raw_parts(ptr, len, capacity) };
assert_eq!(*story, s);
println!("Success!")
}
```
### Common methods
More exercises of String methods can be found [here](../std/String.md).
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,244 @@
# Vector
Vectors are re-sizable arrays. Like slices, their size is not known at compile time, but they can grow or shrink at any time.
### Basic Operations
1. 🌟🌟🌟
```rust,editable
fn main() {
let arr: [u8; 3] = [1, 2, 3];
let v = Vec::from(arr);
is_vec(v);
let v = vec![1, 2, 3];
is_vec(v);
// vec!(..) and vec![..] are same macros, so
let v = vec!(1, 2, 3);
is_vec(v);
// in code below, v is Vec<[u8; 3]> , not Vec<u8>
// USE Vec::new and `for` to rewrite the below code
let v1 = vec!(arr);
is_vec(v1);
assert_eq!(v, v1);
println!("Success!")
}
fn is_vec(v: Vec<u8>) {}
```
2. 🌟🌟 a Vec can be extended with `extend` method
```rust,editable
// FILL in the blank
fn main() {
let mut v1 = Vec::from([1, 2, 4]);
v1.pop();
v1.push(3);
let mut v2 = Vec::new();
v2.__;
assert_eq!(v1, v2);
println!("Success!")
}
```
### Turn X Into Vec
3. 🌟🌟🌟
```rust,editable
// FILL in the blanks
fn main() {
// array -> Vec
// impl From<[T; N]> for Vec
let arr = [1, 2, 3];
let v1 = __(arr);
let v2: Vec<i32> = arr.__();
assert_eq!(v1, v2);
// String -> Vec
// impl From<String> for Vec
let s = "hello".to_string();
let v1: Vec<u8> = s.__();
let s = "hello".to_string();
let v2 = s.into_bytes();
assert_eq!(v1, v2);
// impl<'_> From<&'_ str> for Vec
let s = "hello";
let v3 = Vec::__(s);
assert_eq!(v2, v3);
// Iterators can be collected into vectors
let v4: Vec<i32> = [0; 10].into_iter().collect();
assert_eq!(v4, vec![0; 10]);
println!("Success!")
}
```
### Indexing
4. 🌟🌟🌟
```rust,editable
// FIX the error and IMPLEMENT the code
fn main() {
let mut v = Vec::from([1, 2, 3]);
for i in 0..5 {
println!("{:?}", v[i])
}
for i in 0..5 {
// IMPLEMENT the code here...
}
assert_eq!(v, vec![2, 3, 4, 5, 6]);
println!("Success!")
}
```
### Slicing
A Vec can be mutable. On the other hand, slices are read-only objects. To get a slice, use `&`.
In Rust, its more common to pass slices as arguments rather than vectors when you just want to provide read access. The same goes for `String` and `&str`.
5. 🌟🌟
```rust,editable
// FIX the errors
fn main() {
let mut v = vec![1, 2, 3];
let slice1 = &v[..];
// out of bounds will cause a panic
// You must use `v.len` here
let slice2 = &v[0..4];
assert_eq!(slice1, slice2);
// slice are read only
// Note: slice and &Vec are different
let vec_ref: &mut Vec<i32> = &mut v;
(*vec_ref).push(4);
let slice3 = &mut v[0..3];
slice3.push(4);
assert_eq!(slice3, &[1, 2, 3, 4]);
println!("Success!")
}
```
### Capacity
The capacity of a vector is the amount of space allocated for any future elements that will be added onto the vector. This is not to be confused with the length of a vector, which specifies the number of actual elements within the vector. If a vectors length exceeds its capacity, its capacity will automatically be increased, but its elements will have to be reallocated.
For example, a vector with capacity 10 and length 0 would be an empty vector with space for 10 more elements. Pushing 10 or fewer elements onto the vector will not change its capacity or cause reallocation to occur. However, if the vectors length is increased to 11, it will have to reallocate, which can be slow. For this reason, it is recommended to use `Vec::with_capacity `whenever possible to specify how big the vector is expected to get.
6. 🌟🌟
```rust,editable
// FIX the errors
fn main() {
let mut vec = Vec::with_capacity(10);
// The vector contains no items, even though it has capacity for more
assert_eq!(vec.len(), __);
assert_eq!(vec.capacity(), 10);
// These are all done without reallocating...
for i in 0..10 {
vec.push(i);
}
assert_eq!(vec.len(), __);
assert_eq!(vec.capacity(), __);
// ...but this may make the vector reallocate
vec.push(11);
assert_eq!(vec.len(), 11);
assert!(vec.capacity() >= 11);
// fill in an appropriate value to make the `for` done without reallocating
let mut vec = Vec::with_capacity(__);
for i in 0..100 {
vec.push(i);
}
assert_eq!(vec.len(), __);
assert_eq!(vec.capacity(), __);
println!("Success!")
}
```
### Store distinct types in Vector
The elements in a vector mush be the same type, for example , the code below will cause an error:
```rust
fn main() {
let v = vec![1, 2.0, 3];
}
```
But we can use enums or trait objects to store distinct types.
7. 🌟🌟
```rust,editable
#[derive(Debug)]
enum IpAddr {
V4(String),
V6(String),
}
fn main() {
// FILL in the blank
let v : Vec<IpAddr>= __;
// Comparing two enums need to derive the PartialEq trait
assert_eq!(v[0], IpAddr::V4("127.0.0.1".to_string()));
assert_eq!(v[1], IpAddr::V6("::1".to_string()));
println!("Success!")
}
```
8. 🌟🌟
```rust,editable
trait IpAddr {
fn display(&self);
}
struct V4(String);
impl IpAddr for V4 {
fn display(&self) {
println!("ipv4: {:?}",self.0)
}
}
struct V6(String);
impl IpAddr for V6 {
fn display(&self) {
println!("ipv6: {:?}",self.0)
}
}
fn main() {
// FILL in the blank
let v: __= vec![
Box::new(V4("127.0.0.1".to_string())),
Box::new(V6("::1".to_string())),
];
for ip in v {
ip.display();
}
}
```

295
en/src/comments-docs.md Normal file
View File

@ -0,0 +1,295 @@
# Comments and Docs
Every program requires comments:
## Comments
- Regular comments which are ignored by the compiler:
- `// Line comment, which goes to the end of the line`
- `/* Block comment, which goes to the end of the closing delimiter */`
### Examples
```rust
fn main() {
// This is an example of a line comment
// There are two slashes at the beginning of the line
// And nothing written inside these will be read by the compiler
// println!("Hello, world!");
// Run it. See? Now try deleting the two slashes, and run it again.
/*
* This is another type of comment, a block comment. In general,
* line comments are the recommended comment style. But
* block comments are extremely useful for temporarily disabling
* chunks of code. /* Block comments can be /* nested, */ */
* so it takes only a few keystrokes to comment out everything
* in this main() function. /*/*/* Try it yourself! */*/*/
*/
/*
Note: The previous column of `*` was entirely for style. There's
no actual need for it.
*/
}
```
### Exercises
1. 🌟🌟
```rust,editable
/* Make it work, only using comments! */
fn main() {
todo!();
unimplemented!();
assert_eq!(6, 5 + 3 + 2 + 1 )
}
```
## Doc Comments
- Doc comments which are parsed into HTML and supported `Markdown`
- `/// Generate library docs for the following item`
- `//! Generate library docs for the eclosing item`
Before starting, we need to create a new package for practice: `cargo new --lib doc-comments`.
### Line doc comments `///`
Add docs for function `add_one`
```rust
// in lib.rs
/// Add one to the given value and return the value
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
### Cargo doc
We can use `cargo doc --open` to generate html files and open them in the browser.
### Block doc comments `/** ... */`
Add docs for function `add_two`:
```rust
/** Add two to the given value and return a new value
# Examples
let arg = 5;
let answer = my_crate::add_two(arg);
assert_eq!(7, answer);
*/
pub fn add_two(x: i32) -> i32 {
x + 2
}
```
### Doc comments for crate and module
We can also add doc comments for our crates and modules.
Firstly, let's add some doc comments for our library crate:
> Note: We mush place crates and module comments at the top of the crate root or module file.
```rust
//! # Doc comments
//!
//! A library for showing how to use doc comments
// in lib.rs
pub mod compute;
```
You can also use block comments to achieve this:
```rust
/*! # Doc comments
A library for showing how to use doc comments */
```
Next, create a new module file `src/compute.rs`, and add following comments to it:
```rust
//! //! Do some complicated arithmetic that you can't do by yourself
// in compute.rs
```
Then run `cargo doc --open` and see the results.
### Doc tests
The doc comments of `add_one` and `add_tow` contain two example code blocks.
The examples can not only demonstrate how to use your library, but also running as test with `cargo test` command.
2. 🌟🌟 But there are errors in the two examples, please fix them, and running with `cargo test` to get following result:
```shell
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests doc-comments
running 2 tests
test src/lib.rs - add_one (line 11) ... ok
test src/lib.rs - add_two (line 26) ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.55s
```
3. 🌟🌟 Sometimes we expect an example to be panic, add following code to `src/compute.rs` and make the `cargo test` passed.
> You can only modify the comments, DON'T modify `fn div`
```rust
// in src/compute.rs
/// # Panics
///
/// The function panics if the second argument is zero.
///
/// ```rust,should_panic
/// // panics on division by zero
/// doc_comments::compute::div(10, 0);
/// ```
pub fn div(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Divide-by-zero error");
}
a / b
}
```
4. 🌟🌟 Sometimes we want to hide the doc comments, but keep the doc tests.
Add following code to `src/compute.rs` ,
```rust
// in src/compute.rs
/// ```
/// # fn try_main() -> Result<(), String> {
/// let res = doc_comments::compute::try_div(10, 0)?;
/// # Ok(()) // returning from try_main
/// # }
/// # fn main() {
/// # try_main().unwrap();
/// #
/// # }
/// ```
pub fn try_div(a: i32, b: i32) -> Result<i32, String> {
if b == 0 {
Err(String::from("Divide-by-zero"))
} else {
Ok(a / b)
}
}
```
and modify this code to achieve two goals:
- The doc comments must not be presented in html files generated by `cargo doc --open`
- run the tests, you should see results as below:
```shell
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests doc-comments
running 4 tests
test src/compute.rs - compute::div (line 7) ... ok
test src/lib.rs - add_two (line 27) ... ok
test src/lib.rs - add_one (line 11) ... ok
test src/compute.rs - compute::try_div (line 20) ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.51s
```
### Code navigation
Rust provide a very powerful feature for us, that is code navigation in doc comments.
Add following code to `src/lib.rs`:
```rust
// in lib.rs
/// Add one to the given value and return a [`Option`] type
pub fn add_three(x: i32) -> Option<i32> {
Some(x + 3)
}
```
Besides jump into the standard library, you can also jump to another module in the package.
```rust
// in lib.rs
mod a {
/// Add four to the given value and return a [`Option`] type
/// [`crate::MySpecialFormatter`]
pub fn add_four(x: i32) -> Option<i32> {
Some(x + 4)
}
}
struct MySpecialFormatter;
```
### Doc attributes
Below are a few examples of the most common `#[doc]` attributes used with `rustdoc`.
### `inline`
Used to inline docs, instead of linking out to separate page.
```rust,ignore
#[doc(inline)]
pub use bar::Bar;
/// bar docs
mod bar {
/// the docs for Bar
pub struct Bar;
}
```
### `no_inline`
Used to prevent linking out to separate page or anywhere.
```rust,ignore
// Example from libcore/prelude
#[doc(no_inline)]
pub use crate::mem::drop;
```
### `hidden`
Using this tells `rustdoc` not to include this in documentation:
```rust,editable,ignore
// Example from the futures-rs library
#[doc(hidden)]
pub use self::async_await::*;
```
For documentation, `rustdoc` is widely used by the community. It's what is used to generate the [std library docs](https://doc.rust-lang.org/std/).
### Full Code
The full code of package `doc-comments` is [here](https://github.com/sunface/rust-by-practice/tree/master/practices/doc-comments).

View File

@ -0,0 +1,102 @@
# Array
The type of array is `[T; Lengh]`, as you can see, array's lengh is part of their type signature. So their length must be known at compile time.
For example, you cant initialized an array as below:
```rust
fn init_arr(n: i32) {
let arr = [1; n];
}
```
This will cause an error, because the compile have no idea of the exact size of the array in compile time.
1. 🌟
```rust,editable
fn main() {
// fill the blank with proper array type
let arr: __ = [1, 2, 3, 4, 5];
// modify below to make it work
assert!(arr.len() == 4);
println!("Success!")
}
```
2. 🌟🌟
```rust,editable
fn main() {
// we can ignore parts of the array type or even the whole type, let the compiler infer it for us
let arr0 = [1, 2, 3];
let arr: [_; 3] = ['a', 'b', 'c'];
// fill the blank
// Arrays are stack allocated, `std::mem::size_of_val` return the bytes which array occupies
// A char takes 4 byte in Rust: Unicode char
assert!(std::mem::size_of_val(&arr) == __);
println!("Success!")
}
```
3. 🌟 All elements in an array can be initialized to the same value at once.
```rust,editable
fn main() {
// fill the blank
let list: [i32; 100] = __ ;
assert!(list[0] == 1);
assert!(list.len() == 100);
println!("Success!")
}
```
4. 🌟 All elements in an array must be of the same type
```rust,editable
fn main() {
// fix the error
let _arr = [1, 2, '3'];
println!("Success!")
}
```
5. 🌟 Indexing starts at 0.
```rust,editable
fn main() {
let arr = ['a', 'b', 'c'];
let ele = arr[1]; // only modify this line to make the code work!
assert!(ele == 'a');
println!("Success!")
}
```
6. 🌟 Out of bounds indexing causes `panic`.
```rust,editable
// fix the error
fn main() {
let names = [String::from("Sunfei"), "Sunface".to_string()];
// `get` returns an Option<T>, it's safe to use
let name0 = names.get(0).unwrap();
// but indexing is not safe
let _name1 = &names[2];
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,211 @@
# Enum
1. 🌟🌟 Enums can be created with explicit discriminator.
```rust,editable
// fix the errors
enum Number {
Zero,
One,
Two,
}
enum Number1 {
Zero = 0,
One,
Two,
}
// C-like enum
enum Number2 {
Zero = 0.0,
One = 1.0,
Two = 2.0,
}
fn main() {
// a enum variant can be converted to a integer by `as`
assert_eq!(Number::One, Number1::One);
assert_eq!(Number1::One, Number2::One);
println!("Success!")
}
```
2. 🌟 each enum variant can hold its own data.
```rust,editable
// fill in the blank
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg1 = Message::Move{__}; // instantiating with x = 1, y = 2
let msg2 = Message::Write(__); // instantiating with "hello, world!"
println!("Success!")
}
```
3. 🌟🌟 we can get the data which a enum variant is holding by pattern match
```rust,editable
// fill in the blank and fix the error
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::Move{x: 1, y: 2};
if let Message::Move{__} = msg {
assert_eq!(a, b);
} else {
panic!("NEVER LET THIS RUN");
}
println!("Success!")
}
```
4. 🌟🌟
```rust,editable
// fill in the blank and fix the errors
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msgs: __ = [
Message::Quit,
Message::Move{x:1, y:3},
Message::ChangeColor(255,255,0)
];
for msg in msgs {
show_message(msg)
}
}
fn show_message(msg: Message) {
println!("{}", msg);
}
```
5. 🌟🌟 As there is no `null` in Rust, we have to use enum `Option<T>` to deal the cases when value is absent.
```rust,editable
// fill in the blank to make the `println` work.
// also add some code to prevent the `panic` from running.
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
if let __ = six {
println!("{}", n);
println!("Success!")
}
panic!("NEVER LET THIS RUN");
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
__ => None,
__ => Some(i + 1),
}
}
```
6. 🌟🌟🌟🌟 implement a `linked-list` via enums.
```rust,editable
use crate::List::*;
enum List {
// Cons: Tuple struct that wraps an element and a pointer to the next node
Cons(u32, Box<List>),
// Nil: A node that signifies the end of the linked list
Nil,
}
// Methods can be attached to an enum
impl List {
// Create an empty list
fn new() -> List {
// `Nil` has type `List`
Nil
}
// Consume a list, and return the same list with a new element at its front
fn prepend(self, elem: u32) -> __ {
// `Cons` also has type List
Cons(elem, Box::new(self))
}
// Return the length of the list
fn len(&self) -> u32 {
// `self` has to be matched, because the behavior of this method
// depends on the variant of `self`
// `self` has type `&List`, and `*self` has type `List`, matching on a
// concrete type `T` is preferred over a match on a reference `&T`
// after Rust 2018 you can use self here and tail (with no ref) below as well,
// rust will infer &s and ref tail.
// See https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/default-match-bindings.html
match *self {
// Can't take ownership of the tail, because `self` is borrowed;
// instead take a reference to the tail
Cons(_, ref tail) => 1 + tail.len(),
// Base Case: An empty list has zero length
Nil => 0
}
}
// Return representation of the list as a (heap allocated) string
fn stringify(&self) -> String {
match *self {
Cons(head, __ tail) => {
// `format!` is similar to `print!`, but returns a heap
// allocated string instead of printing to the console
format!("{}, {}", head, tail.__())
},
Nil => {
format!("Nil")
},
}
}
}
fn main() {
// Create an empty linked list
let mut list = List::new();
// Prepend some elements
list = list.prepend(1);
list = list.prepend(2);
list = list.prepend(3);
// Show the final state of the list
println!("linked list has length: {}", list.len());
println!("{}", list.stringify());
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,6 @@
# Compound Types
Learning resources:
- English: [Rust Book 4.3, 5.1, 6.1, 8.2](https://doc.rust-lang.org/book/ch04-03-slices.html)
- 简体中文: [Rust语言圣经 - 复合类型](https://course.rs/basic/compound-type/intro.html)

View File

@ -0,0 +1,100 @@
# Slice
Slices are similar to arrays, but their length is not known at compile time, so you can't use slice directly.
1. 🌟🌟 Here, both `[i32]` and `str` are slice types, but directly using it will cause errors. You have to use the reference of the slice instead: `&[i32]`, `&str`.
```rust,editable
// fix the errors, DON'T add new lines!
fn main() {
let arr = [1, 2, 3];
let s1: [i32] = arr[0..2];
let s2: str = "hello, world" as str;
println!("Success!")
}
```
A slice reference is a two-word object, for simplicity reasons, from now on we will use slice instead of `slice reference`. The first word is a pointer to the data, and the second word is the length of the slice. The word size is the same as usize, determined by the processor architecture eg 64 bits on an x86-64. Slices can be used to borrow a section of an array, and have the type signature `&[T]`.
2. 🌟🌟🌟
```rust,editable
fn main() {
let arr: [char; 3] = ['中', '国', '人'];
let slice = &arr[..2];
// modify '6' to make it work
// TIPS: slice( reference ) IS NOT an array, if it is an array, then `assert!` will passed: each of the two UTF-8 chars '中' and '国' occupies 3 bytes, 2 * 3 = 6
assert!(std::mem::size_of_val(&slice) == 6);
println!("Success!")
}
```
3. 🌟🌟
```rust,editable
fn main() {
let arr: [i32; 5] = [1, 2, 3, 4, 5];
// fill the blanks to make the code work
let slice: __ = __;
assert_eq!(slice, &[2, 3, 4]);
println!("Success!")
}
```
### string slices
4. 🌟
```rust,editable
fn main() {
let s = String::from("hello");
let slice1 = &s[0..2];
// fill the blank to make the code work, DON'T USE 0..2 again
let slice2 = &s[__];
assert_eq!(slice1, slice2);
println!("Success!")
}
```
5. 🌟
```rust,editable
fn main() {
let s = "你好,世界";
// modify this line to make the code work
let slice = &s[0..2];
assert!(slice == "你");
println!("Success!")
}
```
6. 🌟🌟 `&String` can be implicitly converted into `&str`.
```rust,editable
// fix errors
fn main() {
let mut s = String::from("hello world");
// here, &s is `&String` type, but `first_word` need a `&str` type.
// it works because `&String` can be implicitly converted to `&str, If you want know more ,this is called `Deref`
let word = first_word(&s);
s.clear(); // error!
println!("the first word is: {}", word);
}
fn first_word(s: &str) -> &str {
&s[..1]
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,266 @@
# string
The type of string literal `"hello, world"` is `&str`, e.g `let s: &str = "hello, world"`.
### str and &str
1. 🌟 We can't use `str` type in normal ways, but we can use `&str`
```rust,editable
// fix error without adding new line
fn main() {
let s: str = "hello, world";
println!("Success!")
}
```
2. 🌟🌟 We can only use `str` by boxed it, `&` can be used to convert `Box<str>` to `&str`
```rust,editable
// fix the error with at least two solutions
fn main() {
let s: Box<str> = "hello, world".into();
greetings(s)
}
fn greetings(s: &str) {
println!("{}",s)
}
```
### String
`String` type is defined in std and stored as a vector of bytes (Vec<u8>), but guaranteed to always be a valid UTF-8 sequence. String is heap allocated, growable and not null terminated.
3. 🌟
```rust,editable
// fill the blank
fn main() {
let mut s = __;
s.push_str("hello, world");
s.push('!');
assert_eq!(s, "hello, world!");
println!("Success!")
}
```
4. 🌟🌟🌟
```rust,editable
// fix all errors without adding newline
fn main() {
let s = String::from("hello");
s.push(',');
s.push(" world");
s += "!".to_string();
println!("{}", s)
}
```
5. 🌟🌟 `replace` can be used to replace substring
```rust,editable
// fill the blank
fn main() {
let s = String::from("I like dogs");
// Allocate new memory and store the modified string there
let s1 = s.__("dogs", "cats");
assert_eq!(s1, "I like cats");
println!("Success!")
}
```
More `String` methods can be found under [String](https://doc.rust-lang.org/std/string/struct.String.html) module.
6. 🌟🌟 You can only concat a `String` with `&str`, and `String`'s ownership can be moved to another variable
```rust,editable
// fix errors without removing any line
fn main() {
let s1 = String::from("hello,");
let s2 = String::from("world!");
let s3 = s1 + s2;
assert_eq!(s3,"hello,world!");
println!("{}",s1);
}
```
### &str and String
Opsite to the seldom using of `str`, `&str` and `String` are used everywhere!
7. 🌟🌟 `&str` can be converted to `String` in two ways
```rust,editable
// fix error with at lest two solutions
fn main() {
let s = "hello, world";
greetings(s)
}
fn greetings(s: String) {
println!("{}",s)
}
```
8. 🌟🌟 We can use `String::from` or `to_string` to convert a `&str` to `String`
```rust,editable
// use two approaches to fix the error and without adding a new line
fn main() {
let s = "hello, world".to_string();
let s1: &str = s;
println!("Success!")
}
```
### string escapes
9. 🌟
```rust,editable
fn main() {
// You can use escapes to write bytes by their hexadecimal values
// fill the blank below to show "I'm writing Rust"
let byte_escape = "I'm writing Ru\x73__!";
println!("What are you doing\x3F (\\x3F means ?) {}", byte_escape);
// ...or Unicode code points.
let unicode_codepoint = "\u{211D}";
let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
println!("Unicode character {} (U+211D) is called {}",
unicode_codepoint, character_name );
let long_string = "String literals
can span multiple lines.
The linebreak and indentation here \
can be escaped too!";
println!("{}", long_string);
}
```
10. 🌟🌟🌟 Sometimes there are just too many characters that need to be escaped or it's just much more convenient to write a string out as-is. This is where raw string literals come into play.
```rust,editable
fn main() {
let raw_str = r"Escapes don't work here: \x3F \u{211D}";
// modify below line to make it work
assert_eq!(raw_str, "Escapes don't work here: ? ");
// If you need quotes in a raw string, add a pair of #s
let quotes = r#"And then I said: "There is no escape!""#;
println!("{}", quotes);
// If you need "# in your string, just use more #s in the delimiter.
// You can use up to 65535 #s.
let delimiter = r###"A string with "# in it. And even "##!"###;
println!("{}", delimiter);
// fill the blank
let long_delimiter = __;
assert_eq!(long_delimiter, "Hello, \"##\"");
println!("Success!")
}
```
### byte string
Want a string that's not UTF-8? (Remember, str and String must be valid UTF-8). Or maybe you want an array of bytes that's mostly text? Byte strings to the rescue!
**Example**:
```rust,editable
use std::str;
fn main() {
// Note that this is not actually a `&str`
let bytestring: &[u8; 21] = b"this is a byte string";
// Byte arrays don't have the `Display` trait, so printing them is a bit limited
println!("A byte string: {:?}", bytestring);
// Byte strings can have byte escapes...
let escaped = b"\x52\x75\x73\x74 as bytes";
// ...but no unicode escapes
// let escaped = b"\u{211D} is not allowed";
println!("Some escaped bytes: {:?}", escaped);
// Raw byte strings work just like raw strings
let raw_bytestring = br"\u{211D} is not escaped here";
println!("{:?}", raw_bytestring);
// Converting a byte array to `str` can fail
if let Ok(my_str) = str::from_utf8(raw_bytestring) {
println!("And the same as text: '{}'", my_str);
}
let _quotes = br#"You can also use "fancier" formatting, \
like with normal raw strings"#;
// Byte strings don't have to be UTF-8
let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // "ようこそ" in SHIFT-JIS
// But then they can't always be converted to `str`
match str::from_utf8(shift_jis) {
Ok(my_str) => println!("Conversion successful: '{}'", my_str),
Err(e) => println!("Conversion failed: {:?}", e),
};
}
```
A more detailed listing of the ways to write string literals and escape characters is given in the ['Tokens' chapter](https://doc.rust-lang.org/reference/tokens.html) of the Rust Reference.
### string index
11. 🌟🌟🌟 You can't use index to access a char in a string, but you can use slice `&s1[start..end]`.
```rust,editable
fn main() {
let s1 = String::from("hi,中国");
let h = s1[0]; //modify this line to fix the error, tips: `h` only takes 1 byte in UTF8 format
assert_eq!(h, "h");
let h1 = &s1[3..5];//modify this line to fix the error, tips: `` takes 3 bytes in UTF8 format
assert_eq!(h1, "中");
println!("Success!")
}
```
### operate on UTF8 string
12. 🌟
```rust,editable
fn main() {
// fill the blank to print each char in "你好,世界"
for c in "你好,世界".__ {
println!("{}", c)
}
}
```
#### utf8_slice
You can use [utf8_slice](https://docs.rs/utf8_slice/1.0.0/utf8_slice/fn.slice.html) to slice UTF8 string, it can index chars instead of bytes.
**Example**
```rust
use utf8_slice;
fn main() {
let s = "The 🚀 goes to the 🌑!";
let rocket = utf8_slice::slice(s, 4, 5);
// Will equal "🚀"
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,231 @@
# Struct
### There types of structs
1. 🌟 We must specify concrete values for each of the fields in struct.
```rust,editable
// fix the error
struct Person {
name: String,
age: u8,
hobby: String
}
fn main() {
let age = 30;
let p = Person {
name: String::from("sunface"),
age,
};
println!("Success!")
}
```
2. 🌟 Unit struct don't have any fields. It can be useful when you need to implement a trait on some type but dont have any data that you want to store in the type itself.
```rust,editable
struct Unit;
trait SomeTrait {
// ...Some behavours defines here
}
// We don't care the the fields are in Unit, but we care its behaviors.
// So we use a struct with no fields and implement some behaviors for it
impl SomeTrait for Unit { }
fn main() {
let u = Unit;
do_something_with_unit(u);
println!("Success!")
}
// fill the blank to make the code work
fn do_something_with_unit(u: __) { }
```
3. 🌟🌟🌟 Tuple struct looks similar to tuples, it has added meaning the struct name provides but has no named fields. It's useful when you want give the whole tuple a name, but don't care the fields's names.
```rust,editable
// fix the error and fill the blanks
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
fn main() {
let v = Point(__, __, __);
check_color(v);
println!("Success!")
}
fn check_color(p: Color) {
let (x, _, _) = p;
assert_eq!(x, 0);
assert_eq!(p.1, 127);
assert_eq!(__, 255);
}
```
### Operate on structs
4. 🌟 You can make a whole struct mutable when instantiate it, but Rust doesn't allow us to mark only certain fields as mutable.
```rust,editable
// fill the blank and fix the error without adding/removing new line
struct Person {
name: String,
age: u8,
}
fn main() {
let age = 18;
let p = Person {
name: String::from("sunface"),
age,
};
// how can you believe sunface is only 18?
p.age = 30;
// fill the lank
__ = String::from("sunfei");
println!("Success!")
}
```
5. 🌟 Using *field init shorthand syntax* to reduct repetitions.
```rust,editable
// fill the blank
struct Person {
name: String,
age: u8,
}
fn main() {
println!("Success!")
}
fn build_person(name: String, age: u8) -> Person {
Person {
age,
__
}
}
```
6. 🌟 You can create instance from other instance with *struct update syntax*
```rust,editable
// fill the blank to make the code work
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let u1 = User {
email: String::from("someone@example.com"),
username: String::from("sunface"),
active: true,
sign_in_count: 1,
};
let u2 = set_email(u1);
println!("Success!")
}
fn set_email(u: User) -> User {
User {
email: String::from("contact@im.dev"),
__
}
}
```
### Print the structs
7. 🌟🌟 We can use `#[derive(Debug)]` to [make a struct prinable](https://doc.rust-lang.org/book/ch05-02-example-structs.html?highlight=%23%5Bderive(Debug)%5D#adding-useful-functionality-with-derived-traits).
```rust,editable
// fill the blanks to make the code work
#[__]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let scale = 2;
let rect1 = Rectangle {
width: dbg!(30 * scale), // print debug info to stderr and assign the value of `30 * scale` to `width`
height: 50,
};
dbg!(&rect1); // print debug info to stderr
println!(__, rect1); // print debug info to stdout
}
```
### Partial move
Within the destructuring of a single variable, both by-move and by-reference pattern bindings can be used at the same time. Doing this will result in a partial move of the variable, which means that parts of the variable will be moved while other parts stay. In such a case, the parent variable cannot be used afterwards as a whole, however the parts that are only referenced (and not moved) can still be used.
#### Example
```rust,editable
fn main() {
#[derive(Debug)]
struct Person {
name: String,
age: Box<u8>,
}
let person = Person {
name: String::from("Alice"),
age: Box::new(20),
};
// `name` is moved out of person, but `age` is referenced
let Person { name, ref age } = person;
println!("The person's age is {}", age);
println!("The person's name is {}", name);
// Error! borrow of partially moved value: `person` partial move occurs
//println!("The person struct is {:?}", person);
// `person` cannot be used but `person.age` can be used as it is not moved
println!("The person's age from person struct is {}", person.age);
}
```
#### Exercises
8. 🌟🌟
```rust,editable
// fix errors to make it work
#[derive(Debug)]
struct File {
name: String,
data: String,
}
fn main() {
let f = File {
name: String::from("readme.md"),
data: "Rust By Practice".to_string()
};
let _name = f.name;
// ONLY modify this line
println!("{}, {}, {:?}",f.name, f.data, f);
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,89 @@
# Tuple
1. 🌟 Elements in a tuple can have different types. Tuple's type signature is `(T1, T2, ...)`, where `T1`, `T2` are the types of tuple's members.
```rust,editable
fn main() {
let _t0: (u8,i16) = (0, -1);
// Tuples can be tuple's members
let _t1: (u8, (i16, u32)) = (0, (-1, 1));
// fill the blanks to make the code work
let t: (u8, __, i64, __, __) = (1u8, 2u16, 3i64, "hello", String::from(", world"));
println!("Success!")
}
```
2. 🌟 Members can be extracted from the tuple using indexing.
```rust,editable
// make it works
fn main() {
let t = ("i", "am", "sunface");
assert_eq!(t.1, "sunface");
println!("Success!")
}
```
3. 🌟 Long tuples cannot be printed
```rust,editable
// fix the error
fn main() {
let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
println!("too long tuple: {:?}", too_long_tuple);
}
```
4. 🌟 Destructuring tuple with pattern.
```rust,editable
fn main() {
let tup = (1, 6.4, "hello");
// fill the blank to make the code work
let __ = tup;
assert_eq!(x, 1);
assert_eq!(y, "hello");
assert_eq!(z, 6.4);
println!("Success!")
}
```
5. 🌟🌟 Destructure assignments.
```rust,editable
fn main() {
let (x, y, z);
// fill the blank
__ = (1, 2, 3);
assert_eq!(x, 3);
assert_eq!(y, 1);
assert_eq!(z, 2);
println!("Success!")
}
```
6. 🌟🌟 Tuples can be used as function arguments and return values
```rust,editable
fn main() {
// fill the blank, need a few computations here.
let (x, y) = sum_multiply(__);
assert_eq!(x, 5);
assert_eq!(y, 6);
println!("Success!")
}
fn sum_multiply(nums: (i32, i32)) -> (i32, i32) {
(nums.0 + nums.1, nums.0 * nums.1)
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,109 @@
# Package and Crate
A package is a project which you create with Cargo (most cases), so it contains a `Cargo.toml` file in it.
1. 🌟 Create a package with below layout:
```shell
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
```
```toml
# in Cargo.toml
[package]
name = "hello-package"
version = "0.1.0"
edition = "2021"
```
> Note! We will use this package across the whole chapter as a practice project.
2. 🌟 Create a package with below layout:
```shell
.
├── Cargo.toml
└── src
└── lib.rs
1 directory, 2 files
```
```toml
# in Cargo.toml
[package]
name = "hello-package1"
version = "0.1.0"
edition = "2021"
```
> Note! This package could be safely removed due to the first one's existence.
3. 🌟
```rust,editable
/* FILL in the blank with your ANSWER */
// Q: Whats the difference between package 1# and 2# ?
// A: __
```
## Crate
A crate is a binary or library. The crate root is a source file that the Rust compiler starts from and makes up the root module of the crate.
In package `hello-package`, there is binary crate with the same name as the package : `hello-package`, and `src/main.rs` is the crate root of this binary crate.
Similar to `hello-package`, `hello-package1` also has a crate in it, however, this package doesn't contain a binary crate but a library crate, and `src/lib.rs` is the crate root.
4. 🌟
```rust,editable
/* FILL in the blank with your ANSWER */
// Q: Whats the name of the library crate in package `hello-package1`?
// A: __
```
5. 🌟🌟 Add a library crate for `hello-package` and describe it's files tree below:
```shell,editable
# FILL in the blanks
.
├── Cargo.lock
├── Cargo.toml
├── src
│   ├── __
│   └── __
```
After this step, there should be two crates in package `hello-package`: **a binary crate and a library crate, both with the same name as the package**.
6. 🌟🌟🌟 A package can contain at most one library crate, but it can contain as many binary crates as you would like by placing files in `src/bin` directory: **each file will be a separate binary crate with the same name as the file**.
```shell,editable
# Create a package which contains
# 1. three binary crates: `hello-package`, `main1` and `main2`
# 2. one library crate
# describe the directory tree below
.
├── Cargo.toml
├── Cargo.lock
├── src
│ ├── __
│ ├── __
│ └── __
│ └── __
│ └── __
├── tests # directory for integrated tests files
│ └── some_integration_tests.rs
├── benches # dir for benchmark files
│ └── simple_bench.rs
└── examples # dir for example files
└── simple_example.rs
```
Yep, as you can see, the above package structure is very standard and is widely used in many Rust projects.
> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,5 @@
# Crate and module
Learning resources:
- English: [Rust Book Chapter 7](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
- 简体中文: [Rust语言圣经 - 包和模块](https://course.rs/basic/crate-module/intro.html)

View File

@ -0,0 +1,195 @@
# Module
Modules let us organize the code within a crate into groups by readablity and easy reuse. Module also controls the privacy of items, which is whether an item can be seen by outside code( public ), or is just an internal implementation and not available for outside code( private ).
We have created a package named `hello-package` in previous chapter, and it looks like this:
```shell
.
├── Cargo.toml
├── src
│   ├── lib.rs
│   └── main.rs
```
Now it's time to create some modules in the library crate and use them in the binary crate, let's start.
1. 🌟🌟 Implement module `front_of_house` based on the module tree below:
```shell
library crate root
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
├── take_payment
└── complain
```
```rust,editable
// FILL in the blank
// in __.rs
mod front_of_house {
// IMPLEMENT this module..
}
```
2. 🌟🌟 Let's call `add_to_waitlist` from a function `eat_at_restaurant` which within the library crate root.
```rust
// in lib.rs
// FILL in the blanks and FIX the errors
// You need make something public with `pub` to provide accessiblity for outside code `fn eat_at_restaurant()`
mod front_of_house {
/* ...snip... */
}
pub fn eat_at_restaurant() {
// call add_to_waitlist with **absolute path**:
__.add_to_waitlist();
// call with **relative path**
__.add_to_waitlist();
}
```
3. 🌟🌟 You can use `super` to import items within the parent module
```rust,editable
// in lib.rs
mod back_of_house {
fn fix_incorrect_order() {
cook_order();
// FILL in the blank in tree ways
//1. using keyword `super`
//2. using absolute path
__.serve_order();
}
fn cook_order() {}
}
```
### Separating modules into different files
```rust
// in lib.rs
pub mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
pub fn seat_at_table() -> String {
String::from("sit down please")
}
}
pub mod serving {
pub fn take_order() {}
pub fn serve_order() {}
pub fn take_payment() {}
// Maybe you don't want the guest hearing the your complaining about them
// So just make it private
fn complain() {}
}
}
pub fn eat_at_restaurant() -> String {
front_of_house::hosting::add_to_waitlist();
back_of_house::cook_order();
String::from("yummy yummy!")
}
pub mod back_of_house {
pub fn fix_incorrect_order() {
cook_order();
crate::front_of_house::serving::serve_order();
}
pub fn cook_order() {}
}
```
4. 🌟🌟🌟🌟 Please separate the modules and codes above into files resident in below dir tree :
```shell
.
├── Cargo.toml
├── src
│   ├── back_of_house.rs
│   ├── front_of_house
│   │   ├── hosting.rs
│   │   ├── mod.rs
│   │   └── serving.rs
│   ├── lib.rs
│   └── main.rs
```
```rust,editable
// in src/lib.rs
// IMPLEMENT...
```
```rust,editable
// in src/back_of_house.rs
// IMPLEMENT...
```
```rust,editable
// in src/front_of_house/mod.rs
// IMPLEMENT...
```
```rust,editable
// in src/front_of_house/hosting.rs
// IMPLEMENT...
```
```rust,editable
// in src/front_of_house/serving.rs
// IMPLEMENT...
```
### accessing code in library crate from binary crate
**Please ensure you have completed the 4th exercise before making further progress.**
You should have below structures and the corresponding codes in them when reaching here:
```shell
.
├── Cargo.toml
├── src
│   ├── back_of_house.rs
│   ├── front_of_house
│   │   ├── hosting.rs
│   │   ├── mod.rs
│   │   └── serving.rs
│   ├── lib.rs
│   └── main.rs
```
5. 🌟🌟🌟 Now we will call a few library functions from the binary crate.
```rust,editable
// in src/main.rs
// FILL in the blank and FIX the errors
fn main() {
assert_eq!(__, "sit down please");
assert_eq!(__,"yummy yummy!");
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,69 @@
# use and pub
1. 🌟 We can bring two types of the same name into the same scope with use, but you need `as` keyword.
```rust,editable
use std::fmt::Result;
use std::io::Result;
fn main() {}
```
2. 🌟🌟 If we are using multiple items defined in the same crate or module, then listing each item on its own line will take up too much verticall space.
```rust,editable
// FILL in the blank in two ways
// DON'T add new code line
use std::collections::__;
fn main() {
let _c1:HashMap<&str, i32> = HashMap::new();
let mut c2 = BTreeMap::new();
c2.insert(1, "a");
let _c3: HashSet<i32> = HashSet::new();
}
```
### Re-exporting names with `pub use`
3. 🌟🌟🌟 In our recently created package `hello-package`, add something to make the below code work
```rust,editable
fn main() {
assert_eq!(hello_package::hosting::seat_at_table(), "sit down please");
assert_eq!(hello_package::eat_at_restaurant(),"yummy yummy!");
}
```
### pub(in Crate)
Sometimes we want an item only be public to a certain crate, then we can use the `pub(in Crate)` syntax.
#### Example
```rust,editable
pub mod a {
pub const I: i32 = 3;
fn semisecret(x: i32) -> i32 {
use self::b::c::J;
x + J
}
pub fn bar(z: i32) -> i32 {
semisecret(I) * z
}
pub fn foo(y: i32) -> i32 {
semisecret(I) + y
}
mod b {
pub(in crate::a) mod c {
pub(in crate::a) const J: i32 = 4;
}
}
}
```
### Full Code
The full code of `hello-package` is [here](https://github.com/sunface/rust-by-practice/tree/master/practices/hello-package).
> You can find the solutions [here](https://github.com/sunface/rust-by-practice) (under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,31 @@
# Small projects with Elegant code base
Following questions come up weekly in online Rust discussions:
- I just finished reading The Book, what should I do next ?
- What projects would you recommend to a Rust beginner?
- Looking for small projects with an elegant code base
- Codes that is easy to read and learn
The answers to these questions are always **Practice**: doing some exercises, and then reading some small and excellent Rust projects.
This is precisely the goal of this book, so, collecting relative resourses and representing in _Rust By Practice_ seems not a bad idea.
### 1. Ripgrep
Answers for above questions usually came with [`ripgrep`](https://github.com/BurntSushi/ripgrep), though I don't think it is a **small** project, but yes, go for it if you are not afraid to delve deep a bit.
### 2. Building a text editor
Tutorial [`https://www.philippflenker.com/hecto/`](https://www.philippflenker.com/hecto/) will lead you to build a text editor from scratch.
### 3. Ncspot
[Ncspot](https://github.com/hrkfdn/ncspot), a terminal Spotify client. Small, simple, well organized and async, it's good for learning.
### 4. Command Line Rust
[This project](https://github.com/kyclark/command-line-rust) is for the book `Command-Line Rust(O'Reily)` ,it will show you how to write small CLIS( clones of head, cat, ls).
### 5. pngme book
[This book](https://picklenerd.github.io/pngme_book/) will guide you to make a command line program that lets you hide secret messages in PNG files. The primary goal here is to get you writing code. The secondary goal is to get you reading documentation.
**To be continued...**

1
en/src/errors.md Normal file
View File

@ -0,0 +1 @@
# Errors

View File

@ -0,0 +1,29 @@
# Borrowing
1. 🌟🌟
```rust,editable
// FIX the error without removing any code line
struct test {
list: Vec<i32>,
a: i32
}
impl test {
pub fn new() -> Self {
test { list:vec![1,2,3,4,5,6,7], a:0 }
}
pub fn run(&mut self) {
for i in self.list.iter() {
self.do_something(*i)
}
}
pub fn do_something(&mut self, n: i32) {
self.a = n;
}
}
fn main() {}
```

View File

@ -0,0 +1,4 @@
# Fighting with Compiler
Fighting with compiler is very common in our daily coding, especially for those unfamiliar with Rust.
This chapter will provide some exercises to help us avoid such cases to lower the steep learning curve.

259
en/src/flow-control.md Normal file
View File

@ -0,0 +1,259 @@
# Flow control
### if/else
1. 🌟
```rust,editable
// fill in the blanks
fn main() {
let n = 5;
if n < 0 {
println!("{} is negative", n);
} __ n > 0 {
println!("{} is positive", n);
} __ {
println!("{} is zero", n);
}
}
```
2. 🌟🌟 `if/else` expression can be used in assignments.
```rust,editable
// fix the errors
fn main() {
let n = 5;
let big_n =
if n < 10 && n > -10 {
println!(", and is a small number, increase ten-fold");
10 * n
} else {
println!(", and is a big number, halve the number");
n / 2.0 ;
}
println!("{} -> {}", n, big_n);
}
```
### for
3. 🌟 The `for in` construct can be used to iterate through an Iterator, e.g a range `a..b`.
```rust,editable
fn main() {
for n in 1..=100 { // modify this line to make the code work
if n == 100 {
panic!("NEVER LET THIS RUN")
}
}
println!("Success!")
}
```
4. 🌟🌟
```rust,editable
// fix the errors without adding or removing lines
fn main() {
let names = [String::from("liming"),String::from("hanmeimei")];
for name in names {
// do something with name...
}
println!("{:?}", names);
let numbers = [1, 2, 3];
// the elements in numbers are Copyso there is no move here
for n in numbers {
// do something with name...
}
println!("{:?}", numbers);
}
```
5. 🌟
```rust,editable
fn main() {
let a = [4, 3, 2, 1];
// iterate the indexing and value in 'a'
for (i,v) in a.__ {
println!("The {}th element is {}",i+1,v);
}
}
```
### while
6. 🌟🌟 The `while` keyword can be used to run a loop when a condition is true.
```rust,editable
// fill in the blanks to make the last println! work !
fn main() {
// A counter variable
let mut n = 1;
// Loop while the condition is true
while n __ 10 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
__;
}
println!("n reached {}, soloop is over",n);
}
```
### continue and break
7. 🌟 use `break` to break the loop.
```rust,editable
// fill in the blank
fn main() {
let mut n = 0;
for i in 0..=100 {
if n == 66 {
__
}
n += 1;
}
assert_eq!(n, 66);
println!("Success!")
}
```
8. 🌟🌟 `continue` will skip over the remaining code in current iteration and go to the next iteration.
```rust,editable
// fill in the blanks
fn main() {
let mut n = 0;
for i in 0..=100 {
if n != 66 {
n+=1;
__;
}
__
}
assert_eq!(n, 66);
println!("Success!")
}
```
### loop
9. 🌟🌟 loop is usually used together with `break` or `continue`.
```rust,editable
// fill in the blanks
fn main() {
let mut count = 0u32;
println!("Let's count until infinity!");
// Infinite loop
loop {
count += 1;
if count == 3 {
println!("three");
// Skip the rest of this iteration
__;
}
println!("{}", count);
if count == 5 {
println!("OK, that's enough");
__;
}
}
assert_eq!(count, 5);
println!("Success!")
}
```
10. 🌟🌟 loop is an expression, so we can use it with `break` to return a value
```rust,editable
// fill in the blank
fn main() {
let mut counter = 0;
let result = loop {
counter += 1;
if counter == 10 {
__;
}
};
assert_eq!(result, 20);
println!("Success!")
}
```
11. 🌟🌟🌟 It's possible to break or continue outer loops when dealing with nested loops. In these cases, the loops must be annotated with some 'label, and the label must be passed to the break/continue statement.
```rust,editable
// fill in the blank
fn main() {
let mut count = 0;
'outer: loop {
'inner1: loop {
if count >= 20 {
// This would break only the inner1 loop
break 'inner1; // `break` is also ok
}
count += 2;
}
count += 5;
'inner2: loop {
if count >= 30 {
// This breaks the outer loop
break 'outer;
}
// This will continue the outer loop
continue 'outer;
}
}
assert!(count == __);
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,153 @@
# Debug and Display
All types which want to be printable must implement the `std::fmt` formatting trait: `std::fmt::Debug` or `std::fmt::Display`.
Automatic implementations are only provided for types such as in the `std` library. All others have to be manually implemented.
## Debug
The implementation of `Debug` is very straightfoward: All types can `derive` the `std::fmt::Debug` implementation. This is not true for `std::fmt::Display` which must be manually implemented.
`{:?}` must be used to print out the type which has implemented the `Debug` trait.
```rust
// This structure cannot be printed either with `fmt::Display` or
// with `fmt::Debug`.
struct UnPrintable(i32);
// To make this struct printable with `fmt::Debug`, we can derive the automatic implementations provided by Rust
#[derive(Debug)]
struct DebugPrintable(i32);
```
1. 🌟
```rust,editable
/* Fill in the blanks and Fix the errors */
struct Structure(i32);
fn main() {
// Types in std and Rust have implemented the fmt::Debug trait
println!("__ months in a year.", 12);
println!("Now __ will print!", Structure(3));
}
```
2. 🌟🌟 So `fmt::Debug` definitely makes one type printable, but sacrifices some elegance. Maybe we can get more elegant by replacing `{:?}` with something else( but not `{}` !)
```rust,editable
#[derive(Debug)]
struct Person {
name: String,
age: u8
}
fn main() {
let person = Person { name: "Sunface".to_string(), age: 18 };
/* Make it output:
Person {
name: "Sunface",
age: 18,
}
*/
println!("{:?}", person);
}
```
3. 🌟🌟 We can also manually implement `Debug` trait for our types
```rust,editable
#[derive(Debug)]
struct Structure(i32);
#[derive(Debug)]
struct Deep(Structure);
fn main() {
// The problem with `derive` is there is no control over how
// the results look. What if I want this to just show a `7`?
/* Make it print: Now 7 will print! */
println!("Now {:?} will print!", Deep(Structure(7)));
}
```
## Display
Yeah, `Debug` is simple and easy to use. But sometimes we want to customize the output appearance of our type. This is where `Display` really shines.
Unlike `Debug`, there is no way to derive the implementation of the `Display` trait, we have to manually implement it.
Anotherthing to note: the placefolder for `Display` is `{}` not `{:?}`.
4. 🌟🌟
```rust,editable
/* Make it work*/
use std::fmt;
struct Point2D {
x: f64,
y: f64,
}
impl fmt::Display for Point2D {
/* Implement.. */
}
impl fmt::Debug for Point2D {
/* Implement.. */
}
fn main() {
let point = Point2D { x: 3.3, y: 7.2 };
assert_eq!(format!("{}",point), "Display: 3.3 + 7.2i");
assert_eq!(format!("{:?}",point), "Debug: Complex { real: 3.3, imag: 7.2 }");
println!("Success!")
}
```
### `?` operator
Implementing `fmt::Display` for a structure whose elements must be handled separately is triky. The problem is each `write!` generates a `fmt::Result` which must be handled in the same place.
Fortunately, Rust provides the `?` operator to help us eliminate some unnecessary codes for deaing with `fmt::Result`.
5. 🌟🌟
```rust,editable
/* Make it work */
use std::fmt;
struct List(Vec<i32>);
impl fmt::Display for List {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Extract the value using tuple indexing,
// and create a reference to `vec`.
let vec = &self.0;
write!(f, "[")?;
// Iterate over `v` in `vec` while enumerating the iteration
// count in `count`.
for (count, v) in vec.iter().enumerate() {
// For every element except the first, add a comma.
// Use the ? operator to return on errors.
if count != 0 { write!(f, ", ")?; }
write!(f, "{}", v)?;
}
// Close the opened bracket and return a fmt::Result value.
write!(f, "]")
}
}
fn main() {
let v = List(vec![1, 2, 3]);
assert_eq!(format!("{}",v), "[0: 1, 1: 2, 2: 3]");
println!("Success!")
}
```

View File

@ -0,0 +1,183 @@
# formating
## Positional arguments
1.🌟🌟
```rust,edtiable
/* Fill in the blanks */
fn main() {
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");// => Alice, this is Bob. Bob, this is Alice
assert_eq!(format!("{1}{0}", 1, 2), __);
assert_eq!(format!(__, 1, 2), "2112");
println!("Success!");
}
```
## Named arguments
2.🌟🌟
```rust,editable
fn main() {
println!("{argument}", argument = "test"); // => "test"
/* Fill in the blanks */
assert_eq!(format!("{name}{}", 1, __), "21");
assert_eq!(format!(__,a = "a", b = 'b', c = 3 ), "a 3 b");
/* Fix the error */
// named argument must be placed after other arguments
println!("{abc} {1}", abc = "def", 2);
println!("Success!")
}
```
## Padding with string
3.🌟🌟 By default, you can pad string with spaces
```rust,editable
fn main() {
// the following two are padding with 5 spaces
println!("Hello {:5}!", "x"); // => "Hello x !"
println!("Hello {:1$}!", "x", 5); // => "Hello x !"
/* Fill in the blanks */
assert_eq!(format!("Hello __!", 5, "x"), "Hello x !");
assert_eq!(format!("Hello __!", "x", width = 5), "Hello x !");
println!("Success!")
}
```
4.🌟🌟🌟 Left align, right align, pad with specified characters.
```rust,editable
fn main() {
// left align
println!("Hello {:<5}!", "x"); // => Hello x !
// right align
assert_eq!(format!("Hello __!", "x"), "Hello x!");
// center align
assert_eq!(format!("Hello __!", "x"), "Hello x !");
// left align, pad with '&'
assert_eq!(format!("Hello {:&<5}!", "x"), __);
println!("Success!")
}
```
5.🌟🌟 You can pad numbers with extra zeros.
```rust,editable
fn main() {
println!("Hello {:5}!", 5); // => Hello 5!
println!("Hello {:+}!", 5); // => Hello +5!
println!("Hello {:05}!", 5); // => Hello 00005!
println!("Hello {:05}!", -5); // => Hello -0005!
/* Fill in the blank */
assert!(format!("{number:0>width$}", number=1, width=6) == __);
println!("Success!")
}
```
## precision
6.🌟🌟 Floating point precision
```rust,editable
/* Fill in the blanks */
fn main() {
let v = 3.1415926;
println!("{:.1$}", v, 4); // same as {:.4} => 3.1416
assert_eq!(format!("__", v), "3.14");
assert_eq!(format!("__", v), "+3.14");
assert_eq!(format!("__", v), "3");
println!("Success!")
}
```
7.🌟🌟🌟 string length
```rust,editable
fn main() {
let s = "Hello, world!";
println!("{0:.5}", s); // => Hello
assert_eq!(format!("Hello __!", 3, "abcdefg"), "Hello abc!");
println!("Success!")
}
```
## binary, octal, hex
- format!("{}", foo) -> "3735928559"
- format!("0x{:X}", foo) -> "0xDEADBEEF"
- format!("0o{:o}", foo) -> "0o33653337357"
8.🌟🌟
```rust,editable
fn main() {
assert_eq!(format!("__", 27), "0b11011");
assert_eq!(format!("__", 27), "0o33");
assert_eq!(format!("__", 27), "0x1b");
assert_eq!(format!("__", 27), "0x1B");
println!("{:x}!", 27); // hex with no prefix => 1b
println!("{:#010b}", 27); // pad binary with 0, width = 10, => 0b00011011
println!("Success!")
}
```
## Capture the enviroments
9.🌟🌟🌟
```rust,editable
fn get_person() -> String {
String::from("sunface")
}
fn get_format() -> (usize, usize) {
(4, 1)
}
fn main() {
let person = get_person();
println!("Hello, {person}!");
let (width, precision) = get_format();
let scores = [("sunface", 99.12), ("jack", 60.34)];
/* Make it print:
sunface: 99.1
jack: 60.3
*/
for (name, score) in scores {
println!("{name}: __");
}
}
```
## Others
**Example**
```rust,editable
fn main() {
// exponent
println!("{:2e}", 1000000000); // => 1e9
println!("{:2E}", 1000000000); // => 1E9
// pointer address
let v= vec![1, 2, 3];
println!("{:p}", v.as_ptr()); // => 0x600002324050
// escape
println!("Hello {{}}"); // => Hello {}
}
```

View File

@ -0,0 +1,66 @@
# Formatted output
```rust,editable,ignore,mdbook-runnable
fn main() {
// In general, the `{}` will be automatically replaced with any
// arguments. These will be stringified.
println!("{} days", 31);
// Without a suffix, 31 becomes an i32. You can change what type 31 is
// by providing a suffix. The number 31i64 for example has the type i64.
// There are various optional patterns this works with. Positional
// arguments can be used.
println!("{0}, this is {1}. {1}, this is {0}", "Alice", "Bob");
// As can named arguments.
println!("{subject} {verb} {object}",
object="the lazy dog",
subject="the quick brown fox",
verb="jumps over");
// Special formatting can be specified after a `:`.
println!("{} of {:b} people know binary, the other half doesn't", 1, 2);
// You can right-align text with a specified width. This will output
// " 1". 5 white spaces and a "1".
println!("{number:>width$}", number=1, width=6);
// You can pad numbers with extra zeroes. This will output "000001".
println!("{number:0>width$}", number=1, width=6);
// Rust even checks to make sure the correct number of arguments are
// used.
println!("My name is {0}, {1} {0}", "Bond");
// FIXME ^ Add the missing argument: "James"
// Create a structure named `Structure` which contains an `i32`.
#[allow(dead_code)]
struct Structure(i32);
// However, custom types such as this structure require more complicated
// handling. This will not work.
println!("This struct `{}` won't print...", Structure(3));
// FIXME ^ Comment out this line.
// For Rust 1.58 and above, you can directly capture the argument from
// surrounding variable. Just like the above, this will output
// " 1". 5 white spaces and a "1".
let number: f64 = 1.0;
let width: usize = 6;
println!("{number:>width$}");
}
```
[`std::fmt`][fmt] contains many [`traits`][traits] which govern the display
of text. The base form of two important ones are listed below:
* `fmt::Debug`: Uses the `{:?}` marker. Format text for debugging purposes.
* `fmt::Display`: Uses the `{}` marker. Format text in a more elegant, user
friendly fashion.
Here, we used `fmt::Display` because the std library provides implementations
for these types. To print text for custom types, more steps are required.
Implementing the `fmt::Display` trait automatically implements the
[`ToString`] trait which allows us to [convert] the type to [`String`][string].

View File

@ -0,0 +1,39 @@
# println! and format!
Printing is handled by a series of [`macros`][macros] defined in [`std::fmt`][fmt]
some of which include:
* `format!`: write formatted text to [`String`][string]
* `print!`: same as `format!` but the text is printed to the console (io::stdout).
* `println!`: same as `print!` but a newline is appended.
* `eprint!`: same as `format!` but the text is printed to the standard error (io::stderr).
* `eprintln!`: same as `eprint!`but a newline is appended.
All parse text in the same fashion. As a plus, Rust checks formatting
correctness at compile time.
## `format!`
1.🌟
```rust,editable
fn main() {
let s1 = "hello";
/* Fill in the blank */
let s = format!(__);
assert_eq!(s, "hello, world!");
}
```
## `print!`, `println!`
2.🌟
```rust,editable
fn main() {
/* Fill in the blanks to make it print:
Hello world, I am
Sunface!
*/
__("hello world, ");
__("I am");
__("Sunface!");
}
```

View File

@ -0,0 +1,51 @@
# Closure
下面代码是Rust圣经课程中[闭包](http://course.rs/advance/functional-programing/closure.html#结构体中的闭包)章节的课内练习题答案:
```rust
struct Cacher<T,E>
where
T: Fn(E) -> E,
E: Copy
{
query: T,
value: Option<E>,
}
impl<T,E> Cacher<T,E>
where
T: Fn(E) -> E,
E: Copy
{
fn new(query: T) -> Cacher<T,E> {
Cacher {
query,
value: None,
}
}
fn value(&mut self, arg: E) -> E {
match self.value {
Some(v) => v,
None => {
let v = (self.query)(arg);
self.value = Some(v);
v
}
}
}
}
fn main() {
}
#[test]
fn call_with_different_values() {
let mut c = Cacher::new(|a| a);
let v1 = c.value(1);
let v2 = c.value(2);
assert_eq!(v2, 1);
}
```

View File

@ -0,0 +1 @@
# Functional programing

View File

@ -0,0 +1,21 @@
# Iterator
https://doc.rust-lang.org/stable/rust-by-example/flow_control/for.html#for-and-iterators
```rust,editable
// (all the type annotations are superfluous)
// A reference to a string allocated in read only memory
let pangram: &'static str = "the quick brown fox jumps over the lazy dog";
println!("Pangram: {}", pangram);
// Iterate over words in reverse, no new string is allocated
println!("Words in reverse");
for word in pangram.split_whitespace().rev() {
println!("> {}", word);
}
// Copy chars into a vector, sort and remove duplicates
let mut chars: Vec<char> = pangram.chars().collect();
chars.sort();
chars.dedup();
```

View File

@ -0,0 +1,51 @@
# Closure
下面代码是Rust圣经课程中[闭包](http://course.rs/advance/functional-programing/closure.html#结构体中的闭包)章节的课内练习题答案:
```rust
struct Cacher<T,E>
where
T: Fn(E) -> E,
E: Copy
{
query: T,
value: Option<E>,
}
impl<T,E> Cacher<T,E>
where
T: Fn(E) -> E,
E: Copy
{
fn new(query: T) -> Cacher<T,E> {
Cacher {
query,
value: None,
}
}
fn value(&mut self, arg: E) -> E {
match self.value {
Some(v) => v,
None => {
let v = (self.query)(arg);
self.value = Some(v);
v
}
}
}
}
fn main() {
}
#[test]
fn call_with_different_values() {
let mut c = Cacher::new(|a| a);
let v1 = c.value(1);
let v2 = c.value(2);
assert_eq!(v2, 1);
}
```

View File

@ -0,0 +1 @@
# Functional Programming

View File

@ -0,0 +1,279 @@
# Advance Traits
## Associated types
The use of "Associated types" improves the overall readability of code by moving inner types locally into a trait as output types. For example :
```rust
pub trait CacheableItem: Clone + Default + fmt::Debug + Decodable + Encodable {
type Address: AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash;
fn is_null(&self) -> bool;
}
```
Using of `Address` is much more clearable and convenient than `AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash`.
1. 🌟🌟🌟
```rust,editable
struct Container(i32, i32);
// USING associated types to re-implement trait Contains.
// trait Contains {
// type A;
// type B;
trait Contains<A, B> {
fn contains(&self, _: &A, _: &B) -> bool;
fn first(&self) -> i32;
fn last(&self) -> i32;
}
impl Contains<i32, i32> for Container {
fn contains(&self, number_1: &i32, number_2: &i32) -> bool {
(&self.0 == number_1) && (&self.1 == number_2)
}
// Grab the first number.
fn first(&self) -> i32 { self.0 }
// Grab the last number.
fn last(&self) -> i32 { self.1 }
}
fn difference<A, B, C: Contains<A, B>>(container: &C) -> i32 {
container.last() - container.first()
}
fn main() {
let number_1 = 3;
let number_2 = 10;
let container = Container(number_1, number_2);
println!("Does container contain {} and {}: {}",
&number_1, &number_2,
container.contains(&number_1, &number_2));
println!("First number: {}", container.first());
println!("Last number: {}", container.last());
println!("The difference is: {}", difference(&container));
}
```
## Default Generic Type Parameters
When we use generic type parameters, we can specify a default concrete type for the generic type. This eliminates the need for implementors of the trait to specify a concrete type if the default type works.
2. 🌟🌟
```rust,editable
use std::ops::Sub;
#[derive(Debug, PartialEq)]
struct Point<T> {
x: T,
y: T,
}
// FILL in the blank in three ways: two of them use the default generic parameters, the other one not.
// Notice that the implementation uses the associated type `Output`.
impl __ {
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Point {
x: self.x - other.x,
y: self.y - other.y,
}
}
}
fn main() {
assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 },
Point { x: 1, y: 3 });
println!("Success!")
}
```
## Fully Qualified Syntax
Nothing in Rust prevents a trait from having a method with the same name as another traits method, nor does Rust prevent you from implementing both traits on one type. Its also possible to implement a method directly on the type with the same name as methods from traits.
When calling methods with the same name, we have to use Fully Qualified Syntax.
#### Example
```rust,editable
trait UsernameWidget {
// Get the selected username out of this widget
fn get(&self) -> String;
}
trait AgeWidget {
// Get the selected age out of this widget
fn get(&self) -> u8;
}
// A form with both a UsernameWidget and an AgeWidget
struct Form {
username: String,
age: u8,
}
impl UsernameWidget for Form {
fn get(&self) -> String {
self.username.clone()
}
}
impl AgeWidget for Form {
fn get(&self) -> u8 {
self.age
}
}
fn main() {
let form = Form{
username: "rustacean".to_owned(),
age: 28,
};
// If you uncomment this line, you'll get an error saying
// "multiple `get` found". Because, after all, there are multiple methods
// named `get`.
// println!("{}", form.get());
let username = UsernameWidget::get(&form);
assert_eq!("rustacean".to_owned(), username);
let age = AgeWidget::get(&form); // you can also use `<Form as AgeWidget>::get`
assert_eq!(28, age);
println!("Success!")
}
```
#### Exercise
3. 🌟🌟
```rust,editable
trait Pilot {
fn fly(&self) -> String;
}
trait Wizard {
fn fly(&self) -> String;
}
struct Human;
impl Pilot for Human {
fn fly(&self) -> String {
String::from("This is your captain speaking.")
}
}
impl Wizard for Human {
fn fly(&self) -> String {
String::from("Up!")
}
}
impl Human {
fn fly(&self) -> String {
String::from("*waving arms furiously*")
}
}
fn main() {
let person = Human;
assert_eq!(__, "This is your captain speaking.");
assert_eq!(__, "Up!");
assert_eq!(__, "*waving arms furiously*");
println!("Success!")
}
```
## Supertraits
Sometimes, you might need one trait to use another traits functionality( like the "inheritance" in other languages ). In this case, you need to rely on the dependent trait also being implemented. The trait you rely on is a `supertrait` of the trait youre implementing.
4. 🌟🌟🌟
```rust,editable
trait Person {
fn name(&self) -> String;
}
// Person is a supertrait of Student.
// Implementing Student requires you to also impl Person.
trait Student: Person {
fn university(&self) -> String;
}
trait Programmer {
fn fav_language(&self) -> String;
}
// CompSciStudent (computer science student) is a subtrait of both Programmer
// and Student. Implementing CompSciStudent requires you to impl both supertraits.
trait CompSciStudent: Programmer + Student {
fn git_username(&self) -> String;
}
fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {
format!(
"My name is {} and I attend {}. My favorite language is {}. My Git username is {}",
student.name(),
student.university(),
student.fav_language(),
student.git_username()
)
}
struct CSStudent {
name: String,
university: String,
fav_language: String,
git_username: String
}
// IMPLEMENT the necessary traits for CSStudent to make the code work
impl ...
fn main() {
let student = CSStudent {
name: "Sunfei".to_string(),
university: "XXX".to_string(),
fav_language: "Rust".to_string(),
git_username: "sunface".to_string()
};
// FILL in the blank
println!("{}", comp_sci_student_greeting(__));
}
```
## Orphan Rules
We cant implement external traits on external types. For example, we cant implement the `Display` trait on `Vec<T>` within our own crate, because `Display` and `Vec<T>` are defined in the standard library and arent local to our crate.
This restriction is often called as the orphan rule, so named because the parent type is not present. This rule ensures that other peoples code cant break your code and vice versa.
Its possible to get around this restriction using the newtype pattern, which involves creating a new type in a tuple struct.
5. 🌟🌟
```rust,editable
use std::fmt;
// DEFINE a newtype `Pretty` here
impl fmt::Display for Pretty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{}\"", self.0.clone() + ", world")
}
}
fn main() {
let w = Pretty("hello".to_string());
println!("w = {}", w);
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,145 @@
# Const Generics
Const generics are generic arguments that range over constant values, rather than types or lifetimes. This allows, for instance, types to be parameterized by integers. In fact, there has been one example of const generic types since early on in Rust's development: the array types [T; N], for some type T and N: usize. However, there has previously been no way to abstract over arrays of an arbitrary size: if you wanted to implement a trait for arrays of any size, you would have to do so manually for each possible value. For a long time, even the standard library methods for arrays were limited to arrays of length at most 32 due to this problem.
## Examples
1. Here's an example of a type and implementation making use of const generics: a type wrapping a pair of arrays of the same size.
```rust,editable
struct ArrayPair<T, const N: usize> {
left: [T; N],
right: [T; N],
}
impl<T: Debug, const N: usize> Debug for ArrayPair<T, N> {
// ...
}
```
2. Currently, const parameters may only be instantiated by const arguments of the following forms:
- A standalone const parameter.
- A literal (i.e. an integer, bool, or character).
- A concrete constant expression (enclosed by {}), involving no generic parameters.
```rust,editable
fn foo<const N: usize>() {}
fn bar<T, const M: usize>() {
foo::<M>(); // ok: `M` is a const parameter
foo::<2021>(); // ok: `2021` is a literal
foo::<{20 * 100 + 20 * 10 + 1}>(); // ok: const expression contains no generic parameters
foo::<{ M + 1 }>(); // error: const expression contains the generic parameter `M`
foo::<{ std::mem::size_of::<T>() }>(); // error: const expression contains the generic parameter `T`
let _: [u8; M]; // ok: `M` is a const parameter
let _: [u8; std::mem::size_of::<T>()]; // error: const expression contains the generic parameter `T`
}
fn main() {}
```
3. Const generics can also let us avoid some runtime checks.
```rust
/// A region of memory containing at least `N` `T`s.
pub struct MinSlice<T, const N: usize> {
/// The bounded region of memory. Exactly `N` `T`s.
pub head: [T; N],
/// Zero or more remaining `T`s after the `N` in the bounded region.
pub tail: [T],
}
fn main() {
let slice: &[u8] = b"Hello, world";
let reference: Option<&u8> = slice.get(6);
// We know this value is `Some(b' ')`,
// but the compiler can't know that.
assert!(reference.is_some());
let slice: &[u8] = b"Hello, world";
// Length check is performed when we construct a MinSlice,
// and it's known at compile time to be of length 12.
// If the `unwrap()` succeeds, no more checks are needed
// throughout the `MinSlice`'s lifetime.
let minslice = MinSlice::<u8, 12>::from_slice(slice).unwrap();
let value: u8 = minslice.head[6];
assert_eq!(value, b' ')
}
```
## Exercises
1. 🌟🌟 `<T, const N: usize>` is part of the struct type, it means `Array<i32, 3>` and `Array<i32, 4>` are different types.
```rust,editable
struct Array<T, const N: usize> {
data : [T; N]
}
fn main() {
let arrays = [
Array{
data: [1, 2, 3],
},
Array {
data: [1.0, 2.0, 3.0],
},
Array {
data: [1, 2]
}
];
println!("Success!")
}
```
2. 🌟🌟
```rust,editable
// fill in the blanks to make it work
fn print_array<__>(__) {
println!("{:?}", arr);
}
fn main() {
let arr = [1, 2, 3];
print_array(arr);
let arr = ["hello", "world"];
print_array(arr);
}
```
3. 🌟🌟🌟 Sometimes we want to limit the size of an variable, e.g when using in embedding evironments, then `const expressions` will fit your need.
```rust,editable
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
fn check_size<T>(val: T)
where
Assert<{ core::mem::size_of::<T>() < 768 }>: IsTrue,
{
//...
}
// fix the errors in main
fn main() {
check_size([0u8; 767]);
check_size([0i32; 191]);
check_size(["hello你好"; __]); // size of &str ?
check_size(["hello你好".to_string(); __]); // size of String?
check_size(['中'; __]); // size of char ?
println!("Success!")
}
pub enum Assert<const CHECK: bool> {}
pub trait IsTrue {}
impl IsTrue for Assert<true> {}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,156 @@
# Generics
### Functions
1. 🌟🌟🌟
```rust,editable
// fill in the blanks to make it work
struct A; // Concrete type `A`.
struct S(A); // Concrete type `S`.
struct SGen<T>(T); // Generic type `SGen`.
fn reg_fn(_s: S) {}
fn gen_spec_t(_s: SGen<A>) {}
fn gen_spec_i32(_s: SGen<i32>) {}
fn generic<T>(_s: SGen<T>) {}
fn main() {
// Using the non-generic functions
reg_fn(__); // Concrete type.
gen_spec_t(__); // Implicitly specified type parameter `A`.
gen_spec_i32(__); // Implicitly specified type parameter `i32`.
// Explicitly specified type parameter `char` to `generic()`.
generic::<char>(__);
// Implicitly specified type parameter `char` to `generic()`.
generic(__);
println!("Success!")
}
```
2. 🌟🌟 A function call with explicitly specified type parameters looks like: `fun::<A, B, ...>()`.
```rust,editable
// implement the generic function below
fn sum
fn main() {
assert_eq!(5, sum(2i8, 3i8));
assert_eq!(50, sum(20, 30));
assert_eq!(2.46, sum(1.23, 1.23));
println!("Success!")
}
```
### Struct and `impl`
3. 🌟
```rust,editable
// implement struct Point to make it work
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
println!("Success!")
}
```
4. 🌟🌟
```rust,editable
// modify this struct to make the code work
struct Point<T> {
x: T,
y: T,
}
fn main() {
// DON'T modify here
let p = Point{x: 5, y : "hello".to_string()};
println!("Success!")
}
```
5. 🌟🌟
```rust,editable
// add generic for Val to make the code work, DON'T modify the code in `main`
struct Val {
val: f64,
}
impl Val {
fn value(&self) -> &f64 {
&self.val
}
}
fn main() {
let x = Val{ val: 3.0 };
let y = Val{ val: "hello".to_string()};
println!("{}, {}", x.value(), y.value());
}
```
### Method
6. 🌟🌟🌟
```rust,editable
struct Point<T, U> {
x: T,
y: U,
}
impl<T, U> Point<T, U> {
// implement mixup to make it work, DON'T modify other code
fn mixup
}
fn main() {
let p1 = Point { x: 5, y: 10 };
let p2 = Point { x: "Hello", y: '中'};
let p3 = p1.mixup(p2);
assert_eq!(p3.x, 5);
assert_eq!(p3.y, '中');
println!("Success!")
}
```
7. 🌟🌟
```rust,editable
// fix the errors to make the code work
struct Point<T> {
x: T,
y: T,
}
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
fn main() {
let p = Point{x: 5, y: 10};
println!("{}",p.distance_from_origin())
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,6 @@
# Generics and Traits
Learning resources:
- English: [Rust Book 10.1, 10.2](https://doc.rust-lang.org/book/ch10-00-generics.html)
- 简体中文: [Rust语言圣经 - 模式匹配](https://course.rs/basic/trait/intro.html)

View File

@ -0,0 +1,229 @@
# Trait Object
In [traits chapter](https://practice.rs/generics-traits/traits.html#returning-types-that-implement-traits) we have seen that we can't use `impl Trait` when returning multiple types.
Also one limitation of arrays is that they can only store elements of one type, yeah, enum is a not bad solution when our items are a fixed set of types in compile time, but trait object are more flexible and powerful here.
## Returning Traits with dyn
The Rust compiler needs to know how much space a function's return type requires. Because the different implementations of a trait probably will need different amounts of memoery, this means function need to return a concrete type or the same type when using `impl Trait`, or it can return a trait object with `dyn`.
1. 🌟🌟🌟
```rust,editable
trait Bird {
fn quack(&self) -> String;
}
struct Duck;
impl Duck {
fn swim(&self) {
println!("Look, the duck is swimming")
}
}
struct Swan;
impl Swan {
fn fly(&self) {
println!("Look, the duck.. oh sorry, the swan is flying")
}
}
impl Bird for Duck {
fn quack(&self) -> String{
"duck duck".to_string()
}
}
impl Bird for Swan {
fn quack(&self) -> String{
"swan swan".to_string()
}
}
fn main() {
// FILL in the blank
let duck = __;
duck.swim();
let bird = hatch_a_bird(2);
// this bird has forgotten how to swim, so below line will cause an error
// bird.swim();
// but it can quak
assert_eq!(bird.quack(), "duck duck");
let bird = hatch_a_bird(1);
// this bird has forgotten how to fly, so below line will cause an error
// bird.fly();
// but it can quak too
assert_eq!(bird.quack(), "swan swan");
println!("Success!")
}
// IMPLEMENT this function
fn hatch_a_bird...
```
## Array with trait objects
2. 🌟🌟
```rust,editable
trait Bird {
fn quack(&self);
}
struct Duck;
impl Duck {
fn fly(&self) {
println!("Look, the duck is flying")
}
}
struct Swan;
impl Swan {
fn fly(&self) {
println!("Look, the duck.. oh sorry, the swan is flying")
}
}
impl Bird for Duck {
fn quack(&self) {
println!("{}", "duck duck");
}
}
impl Bird for Swan {
fn quack(&self) {
println!("{}", "swan swan");
}
}
fn main() {
// FILL in the blank to make the code work
let birds __;
for bird in birds {
bird.quack();
// when duck and swan turns into Bird, they all forgot how to fly, only remeber how to quack
// so, the below code will cause an error
// bird.fly();
}
}
```
## `&dyn` and `Box<dyn>`
3. 🌟🌟
```rust,editable
// FILL in the blanks
trait Draw {
fn draw(&self) -> String;
}
impl Draw for u8 {
fn draw(&self) -> String {
format!("u8: {}", *self)
}
}
impl Draw for f64 {
fn draw(&self) -> String {
format!("f64: {}", *self)
}
}
fn main() {
let x = 1.1f64;
let y = 8u8;
// draw x
draw_with_box(__);
// draw y
draw_with_ref(&y);
println!("Success!")
}
fn draw_with_box(x: Box<dyn Draw>) {
x.draw();
}
fn draw_with_ref(x: __) {
x.draw();
}
```
## Static and Dynamic dispatch
when we use trait bounds on generics: the compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter. The code that results from monomorphization is doing static dispatch, which is when the compiler knows what method youre calling at compile time.
When we use trait objects, Rust must use dynamic dispatch. The compiler doesnt know all the types that might be used with the code that is using trait objects, so it doesnt know which method implemented on which type to call. Instead, at runtime, Rust uses the pointers inside the trait object to know which method to call. There is a runtime cost when this lookup happens that doesnt occur with static dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a methods code, which in turn prevents some optimizations.
However, we did get extra flexibility when using dynamic dispatch.
4. 🌟🌟
```rust,editable
trait Foo {
fn method(&self) -> String;
}
impl Foo for u8 {
fn method(&self) -> String { format!("u8: {}", *self) }
}
impl Foo for String {
fn method(&self) -> String { format!("string: {}", *self) }
}
// IMPLEMENT below with generics
fn static_dispatch...
// implement below with trait objects
fn dynamic_dispatch...
fn main() {
let x = 5u8;
let y = "Hello".to_string();
static_dispatch(x);
dynamic_dispatch(&y);
println!("Success!")
}
```
## Object safe
You can only make object-safe traits into trait objects. A trait is object safe if all the methods defined in the trait have the following properties:
- The return type isnt `Self`.
- There are no generic type parameters.
5. 🌟🌟🌟🌟
```rust,editable
// Use at least two approaches to make it work
// DON'T add/remove any code line
trait MyTrait {
fn f(&self) -> Self;
}
impl MyTrait for u32 {
fn f(&self) -> Self { 42 }
}
impl MyTrait for String {
fn f(&self) -> Self { self.clone() }
}
fn my_function(x: Box<dyn MyTrait>) {
x.f()
}
fn main() {
my_function(Box::new(13_u32));
my_function(Box::new(String::from("abc")));
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1,472 @@
# Traits
A trait tells the Rust compiler about functionality a particular type has and can share with other types. We can use traits to define shared behavior in an abstract way. We can use trait bounds to specify that a generic type can be any type that has certain behavior.
> Note: Traits are similar to interfaces in other languages, although with some differences.
## Examples
```rust,editable
struct Sheep { naked: bool, name: String }
trait Animal {
// Associated function signature; `Self` refers to the implementor type.
fn new(name: String) -> Self;
// Method signatures; these will return a string.
fn name(&self) -> String;
fn noise(&self) -> String;
// Traits can provide default method definitions.
fn talk(&self) {
println!("{} says {}", self.name(), self.noise());
}
}
impl Sheep {
fn is_naked(&self) -> bool {
self.naked
}
fn shear(&mut self) {
if self.is_naked() {
// Implementor methods can use the implementor's trait methods.
println!("{} is already naked...", self.name());
} else {
println!("{} gets a haircut!", self.name);
self.naked = true;
}
}
}
// Implement the `Animal` trait for `Sheep`.
impl Animal for Sheep {
// `Self` is the implementor type: `Sheep`.
fn new(name: String) -> Sheep {
Sheep { name: name, naked: false }
}
fn name(&self) -> String {
self.name.clone()
}
fn noise(&self) -> String {
if self.is_naked() {
"baaaaah?".to_string()
} else {
"baaaaah!".to_string()
}
}
// Default trait methods can be overridden.
fn talk(&self) {
// For example, we can add some quiet contemplation.
println!("{} pauses briefly... {}", self.name, self.noise());
}
}
fn main() {
// Type annotation is necessary in this case.
let mut dolly: Sheep = Animal::new("Dolly".to_string());
// TODO ^ Try removing the type annotations.
dolly.talk();
dolly.shear();
dolly.talk();
}
```
## Exercises
1. 🌟🌟
```rust,editable
// fill in the two impl blocks to make the code work
// DON'T modify the code in `main`
trait Hello {
fn say_hi(&self) -> String {
String::from("hi")
}
fn say_something(&self) -> String;
}
struct Student {}
impl Hello for Student {
}
struct Teacher {}
impl Hello for Teacher {
}
fn main() {
let s = Student {};
assert_eq!(s.say_hi(), "hi");
assert_eq!(s.say_something(), "I'm a good student");
let t = Teacher {};
assert_eq!(t.say_hi(), "Hi, I'm your new teacher");
assert_eq!(t.say_something(), "I'm not a bad teacher");
println!("Success!")
}
```
### Derive
The compiler is capable of providing basic implementations for some traits via
the `#[derive]` attribute. For more info, please visit [here](https://doc.rust-lang.org/book/appendix-03-derivable-traits.html).
2. 🌟🌟
```rust,editable
// `Centimeters`, a tuple struct that can be compared
#[derive(PartialEq, PartialOrd)]
struct Centimeters(f64);
// `Inches`, a tuple struct that can be printed
#[derive(Debug)]
struct Inches(i32);
impl Inches {
fn to_centimeters(&self) -> Centimeters {
let &Inches(inches) = self;
Centimeters(inches as f64 * 2.54)
}
}
// ADD some attributes to make the code work!
// DON'T modify other codes!
struct Seconds(i32);
fn main() {
let _one_second = Seconds(1);
println!("One second looks like: {:?}", _one_second);
let _this_is_true = (_one_second == _one_second);
let _this_is_true = (_one_second > _one_second);
let foot = Inches(12);
println!("One foot equals {:?}", foot);
let meter = Centimeters(100.0);
let cmp =
if foot.to_centimeters() < meter {
"smaller"
} else {
"bigger"
};
println!("One foot is {} than one meter.", cmp);
}
```
### Operator
In Rust, many of the operators can be overloaded via traits. That is, some operators can be used to accomplish different tasks based on their input arguments. This is possible because operators are syntactic sugar for method calls. For example, the + operator in a + b calls the add method (as in a.add(b)). This add method is part of the Add trait. Hence, the + operator can be used by any implementor of the Add trait.
3. 🌟🌟
```rust,editable
use std::ops;
// implement fn multiply to make the code work
// As mentiond above, `+` needs `T` to implement `std::ops::Add` Trait
// so, what about `*` ? You can find the answer here: https://doc.rust-lang.org/core/ops/
fn multipl
fn main() {
assert_eq!(6, multiply(2u8, 3u8));
assert_eq!(5.0, multiply(1.0, 5.0));
println!("Success!")
}
```
4. 🌟🌟🌟
```rust,editable
// fix the errors, DON'T modify the code in `main`
use std::ops;
struct Foo;
struct Bar;
struct FooBar;
struct BarFoo;
// The `std::ops::Add` trait is used to specify the functionality of `+`.
// Here, we make `Add<Bar>` - the trait for addition with a RHS of type `Bar`.
// The following block implements the operation: Foo + Bar = FooBar
impl ops::Add<Bar> for Foo {
type Output = FooBar;
fn add(self, _rhs: Bar) -> FooBar {
FooBar
}
}
impl ops::Sub<Foo> for Bar {
type Output = BarFoo;
fn sub(self, _rhs: Foo) -> BarFoo {
BarFoo
}
}
fn main() {
// DON'T modify the below code
// you need to derive some trait for FooBar to make it comparable
assert_eq!(Foo + Bar, FooBar);
assert_eq!(Foo - Bar, BarFoo);
println!("Success!")
}
```
### Use trait as function parameters
Instead of a concrete type for the item parameter, we specify the impl keyword and the trait name. This parameter accepts any type that implements the specified trait.
5. 🌟🌟🌟
```rust,editable
// implement `fn summary` to make the code work
// fix the errors without removing any code line
trait Summary {
fn summarize(&self) -> String;
}
#[derive(Debug)]
struct Post {
title: String,
author: String,
content: String,
}
impl Summary for Post {
fn summarize(&self) -> String {
format!("The author of post {} is {}", self.title, self.author)
}
}
#[derive(Debug)]
struct Weibo {
username: String,
content: String,
}
impl Summary for Weibo {
fn summarize(&self) -> String {
format!("{} published a weibo {}", self.username, self.content)
}
}
fn main() {
let post = Post {
title: "Popular Rust".to_string(),
author: "Sunface".to_string(),
content: "Rust is awesome!".to_string(),
};
let weibo = Weibo {
username: "sunface".to_string(),
content: "Weibo seems to be worse than Tweet".to_string(),
};
summary(post);
summary(weibo);
println!("{:?}", post);
println!("{:?}", weibo);
}
// implement `fn summary` below
```
### Returning Types that Implement Traits
We can also use the impl Trait syntax in the return position to return a value of some type that implements a trait.
However, you can only use impl Trait if youre returning a single type, using Trait Objects instead when you really need to return serveral types.
6. 🌟🌟
```rust,editable
struct Sheep {}
struct Cow {}
trait Animal {
fn noise(&self) -> String;
}
impl Animal for Sheep {
fn noise(&self) -> String {
"baaaaah!".to_string()
}
}
impl Animal for Cow {
fn noise(&self) -> String {
"moooooo!".to_string()
}
}
// Returns some struct that implements Animal, but we don't know which one at compile time.
// FIX the erros here, you can make a fake random, or you can use trait object
fn random_animal(random_number: f64) -> impl Animal {
if random_number < 0.5 {
Sheep {}
} else {
Cow {}
}
}
fn main() {
let random_number = 0.234;
let animal = random_animal(random_number);
println!("You've randomly chosen an animal, and it says {}", animal.noise());
}
```
### Trait bound
The `impl Trait` syntax works for straightforward cases but is actually syntax sugar for a longer form, which is called a trait bound.
When working with generics, the type parameters often must use traits as bounds to stipulate what functionality a type implements.
7. 🌟🌟
```rust, editable
fn main() {
assert_eq!(sum(1, 2), 3);
}
// implement `fn sum` with trait bound in two ways
fn sum<T>(x: T, y: T) -> T {
x + y
}
```
8. 🌟🌟
```rust,editable
// FIX the errors
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self {
x,
y,
}
}
}
impl<T: std::fmt::Debug + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {:?}", self.x);
} else {
println!("The largest member is y = {:?}", self.y);
}
}
}
struct Unit(i32);
fn main() {
let pair = Pair{
x: Unit(1),
y: Unit(3)
};
pair.cmp_display();
}
```
9. 🌟🌟🌟
```rust,editable
// fill in the blanks to make it work
fn example1() {
// `T: Trait` is the commonly used way
// `T: Fn(u32) -> u32` specifies that we can only pass a closure to `T`
struct Cacher<T: Fn(u32) -> u32> {
calculation: T,
value: Option<u32>,
}
impl<T: Fn(u32) -> u32> Cacher<T> {
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
},
}
}
}
let mut cacher = Cacher::new(|x| x+1);
assert_eq!(cacher.value(10), __);
assert_eq!(cacher.value(15), __);
}
fn example2() {
// We can also use `where` to constrain `T`
struct Cacher<T>
where T: Fn(u32) -> u32,
{
calculation: T,
value: Option<u32>,
}
impl<T> Cacher<T>
where T: Fn(u32) -> u32,
{
fn new(calculation: T) -> Cacher<T> {
Cacher {
calculation,
value: None,
}
}
fn value(&mut self, arg: u32) -> u32 {
match self.value {
Some(v) => v,
None => {
let v = (self.calculation)(arg);
self.value = Some(v);
v
},
}
}
}
let mut cacher = Cacher::new(|x| x+1);
assert_eq!(cacher.value(20), __);
assert_eq!(cacher.value(25), __);
}
fn main() {
example1();
example2();
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it :)

View File

@ -0,0 +1 @@
# Global variables

View File

@ -0,0 +1 @@
# advance

62
en/src/lifetime/basic.md Normal file
View File

@ -0,0 +1,62 @@
## Lifetime
1. 🌟
```rust,editable
/* Make it work */
#[derive(Debug)]
struct NoCopyType {}
#[derive(Debug)]
struct Example<'a, 'b> {
a: &'a u32,
b: &'b NoCopyType
}
fn main()
{
/* 'a tied to fn-main stackframe */
let var_a = 35;
let example: Example;
{
/* lifetime 'b tied to new stackframe/scope */
let var_b = NoCopyType {};
/* fixme */
example = Example { a: &var_a, b: &var_b };
}
println!("(Success!) {:?}", example);
}
```
2. 🌟
```rust,editable
#[derive(Debug)]
struct NoCopyType {}
#[derive(Debug)]
#[allow(dead_code)]
struct Example<'a, 'b> {
a: &'a u32,
b: &'b NoCopyType
}
/* Fix function signature */
fn fix_me(foo: &Example) -> &NoCopyType
{ foo.b }
fn main()
{
let no_copy = NoCopyType {};
let example = Example { a: &1, b: &no_copy };
fix_me(&example);
print!("Success!")
}
```

5
en/src/lifetime/intro.md Normal file
View File

@ -0,0 +1,5 @@
# Lifetime
Learning resources:
- English: [Rust Book 10.3](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html)
- 简体中文: [Rust语言圣经 - 生命周期](https://course.rs/advance/lifetime/intro.html)

49
en/src/lifetime/static.md Normal file
View File

@ -0,0 +1,49 @@
# &'static and T: 'static
```rust,editable
use std::fmt::Display;
fn main() {
let mut string = "First".to_owned();
string.push_str(string.to_uppercase().as_str());
print_a(&string);
print_b(&string);
print_c(&string); // Compilation error
print_d(&string); // Compilation error
print_e(&string);
print_f(&string);
print_g(&string); // Compilation error
}
fn print_a<T: Display + 'static>(t: &T) {
println!("{}", t);
}
fn print_b<T>(t: &T)
where
T: Display + 'static,
{
println!("{}", t);
}
fn print_c(t: &'static dyn Display) {
println!("{}", t)
}
fn print_d(t: &'static impl Display) {
println!("{}", t)
}
fn print_e(t: &(dyn Display + 'static)) {
println!("{}", t)
}
fn print_f(t: &(impl Display + 'static)) {
println!("{}", t)
}
fn print_g(t: &'static String) {
println!("{}", t);
}
```

1
en/src/macro.md Normal file
View File

@ -0,0 +1 @@
# macro

273
en/src/method.md Normal file
View File

@ -0,0 +1,273 @@
# Associated function & Method
## Examples
```rust,editable
struct Point {
x: f64,
y: f64,
}
// Implementation block, all `Point` associated functions & methods go in here
impl Point {
// This is an "associated function" because this function is associated with
// a particular type, that is, Point.
//
// Associated functions don't need to be called with an instance.
// These functions are generally used like constructors.
fn origin() -> Point {
Point { x: 0.0, y: 0.0 }
}
// Another associated function, taking two arguments:
fn new(x: f64, y: f64) -> Point {
Point { x: x, y: y }
}
}
struct Rectangle {
p1: Point,
p2: Point,
}
impl Rectangle {
// This is a method
// `&self` is sugar for `self: &Self`, where `Self` is the type of the
// caller object. In this case `Self` = `Rectangle`
fn area(&self) -> f64 {
// `self` gives access to the struct fields via the dot operator
let Point { x: x1, y: y1 } = self.p1;
let Point { x: x2, y: y2 } = self.p2;
// `abs` is a `f64` method that returns the absolute value of the
// caller
((x1 - x2) * (y1 - y2)).abs()
}
fn perimeter(&self) -> f64 {
let Point { x: x1, y: y1 } = self.p1;
let Point { x: x2, y: y2 } = self.p2;
2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
}
// This method requires the caller object to be mutable
// `&mut self` desugars to `self: &mut Self`
fn translate(&mut self, x: f64, y: f64) {
self.p1.x += x;
self.p2.x += x;
self.p1.y += y;
self.p2.y += y;
}
}
// `Pair` owns resources: two heap allocated integers
struct Pair(Box<i32>, Box<i32>);
impl Pair {
// This method "consumes" the resources of the caller object
// `self` desugars to `self: Self`
fn destroy(self) {
// Destructure `self`
let Pair(first, second) = self;
println!("Destroying Pair({}, {})", first, second);
// `first` and `second` go out of scope and get freed
}
}
fn main() {
let rectangle = Rectangle {
// Associated functions are called using double colons
p1: Point::origin(),
p2: Point::new(3.0, 4.0),
};
// Methods are called using the dot operator
// Note that the first argument `&self` is implicitly passed, i.e.
// `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
println!("Rectangle perimeter: {}", rectangle.perimeter());
println!("Rectangle area: {}", rectangle.area());
let mut square = Rectangle {
p1: Point::origin(),
p2: Point::new(1.0, 1.0),
};
// Error! `rectangle` is immutable, but this method requires a mutable
// object
//rectangle.translate(1.0, 0.0);
// TODO ^ Try uncommenting this line
// Okay! Mutable objects can call mutable methods
square.translate(1.0, 1.0);
let pair = Pair(Box::new(1), Box::new(2));
pair.destroy();
// Error! Previous `destroy` call "consumed" `pair`
//pair.destroy();
// TODO ^ Try uncommenting this line
}
```
## Exercises
### Method
1. 🌟🌟 Methods are similar to functions: declare with `fn`, have parameters and a return value. Unlike functions, methods are defined within the context of a struct (or an enum or a trait object), and their first parameter is always `self`, which represents the instance of the struct the method is being called on.
```rust,editable
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// complete the area method which return the area of a Rectangle
fn area
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
assert_eq!(rect1.area(), 1500);
println!("Success!")
}
```
2. 🌟🌟 `self` will take the ownership of current struct instance, however, `&self` will only borrow a reference from the instance
```rust,editable
// Only fill in the blanks, DON'T remove any line!
#[derive(Debug)]
struct TrafficLight {
color: String,
}
impl TrafficLight {
pub fn show_state(__) {
println!("the current state is {}", __.color);
}
}
fn main() {
let light = TrafficLight{
color: "red".to_owned(),
};
// Don't take the ownership of `light` here
light.show_state();
// ..otherwise, there will be an error below
println!("{:?}", light);
}
```
3. 🌟🌟 The `&self` is actually short for `self: &Self`. Within an `impl` block, the type `Self` is an alias for the type that the `impl` block is for. Methods must have a parameter named `self` of type `Self` for their first parameter, so Rust lets you abbreviate this with only the name `self` in the first parameter spot.
```rust,editable
struct TrafficLight {
color: String,
}
impl TrafficLight {
// using `Self` to fill in the blank
pub fn show_state(__) {
println!("the current state is {}", self.color);
}
// fill in the blank, DON'T use any variants of `Self`
pub fn change_state() {
self.color = "green".to_string()
}
}
fn main() {
println!("Success!")
}
```
### Associated function
4. 🌟🌟 All functions defined within an `impl` block are called associated functions because theyre associated with the type named after the `impl`. We can define associated functions that dont have `self` as their first parameter (and thus are not methods) because they dont need an instance of the type to work with.
```rust,editable
#[derive(Debug)]
struct TrafficLight {
color: String,
}
impl TrafficLight {
// 1. implement a assotiated function `new`,
// 2. it will return a TrafficLight contains color "red"
// 3. must use `Self`, DONT use `TrafficLight` in fn signatures or body
pub fn new()
pub fn get_state(&self) -> &str {
&self.color
}
}
fn main() {
let light = TrafficLight::new();
assert_eq!(light.get_state(), "red");
println!("Success!")
}
```
### Multiple `impl` blocks
5. 🌟 Each struct is allowed to have multiple impl blocks.
```rust,editable
struct Rectangle {
width: u32,
height: u32,
}
// using multiple `impl` blocks to rewrite the code below
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
println!("Success!")
}
```
### Enums
6. 🌟🌟🌟 We can also implement methods for enums.
```rust,editable
#[derive(Debug)]
enum TrafficLightColor {
Red,
Yellow,
Green,
}
// implement TrafficLightColor with a method
impl TrafficLightColor {
}
fn main() {
let c = TrafficLightColor::Yellow;
assert_eq!(c.color(), "yellow");
println!("{:?}",c);
}
```
## Practice
@todo
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

1
en/src/newtype-sized.md Normal file
View File

@ -0,0 +1 @@
# newtype and Sized

View File

@ -0,0 +1,186 @@
# Reference and Borrowing
### Reference
1. 🌟
```rust,editable
fn main() {
let x = 5;
// fill the blank
let p = __;
println!("the memory address of x is {:p}", p); // one possible output: 0x16fa3ac84
}
```
2. 🌟
```rust,editable
fn main() {
let x = 5;
let y = &x;
// modify this line only
assert_eq!(5, y);
println!("Success!")
}
```
3. 🌟
```rust,editable
// fix error
fn main() {
let mut s = String::from("hello, ");
borrow_object(s);
println!("Success!")
}
fn borrow_object(s: &String) {}
```
4. 🌟
```rust,editable
// fix error
fn main() {
let mut s = String::from("hello, ");
push_str(s);
println!("Success!")
}
fn push_str(s: &mut String) {
s.push_str("world")
}
```
5. 🌟🌟
```rust,editable
fn main() {
let mut s = String::from("hello, ");
// fill the blank to make it work
let p = __;
p.push_str("world");
println!("Success!")
}
```
#### ref
`ref` can be used to take references to a value, similar to `&`.
6. 🌟🌟🌟
```rust,editable
fn main() {
let c = '中';
let r1 = &c;
// fill the blankdont change other code
let __ r2 = c;
assert_eq!(*r1, *r2);
// check the equality of the two address strings
assert_eq!(get_addr(r1),get_addr(r2));
println!("Success!")
}
// get memory address string
fn get_addr(r: &char) -> String {
format!("{:p}", r)
}
```
### Borrowing rules
7. 🌟
```rust,editable
// remove something to make it work
// don't remove a whole line !
fn main() {
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s;
println!("{}, {}", r1, r2);
println!("Success!")
}
```
#### Mutablity
8. 🌟 Error: Borrow a immutable object as mutable
```rust,editable
fn main() {
//fix error by modifying this line
let s = String::from("hello, ");
borrow_object(&mut s);
println!("Success!")
}
fn borrow_object(s: &mut String) {}
```
9. 🌟🌟 Ok: Borrow a mutable object as immutable
```rust,editable
// this code has no errors!
fn main() {
let mut s = String::from("hello, ");
borrow_object(&s);
s.push_str("world");
println!("Success!")
}
fn borrow_object(s: &String) {}
```
### NLL
10. 🌟🌟
```rust,editable
// comment one line to make it work
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
r1.push_str("world");
let r2 = &mut s;
r2.push_str("!");
println!("{}",r1);
}
```
11. 🌟🌟
```rust,editable
fn main() {
let mut s = String::from("hello, ");
let r1 = &mut s;
let r2 = &mut s;
// add one line below to make a compiler error: cannot borrow `s` as mutable more than once at a time
// you can't use r1 and r2 at the same time
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,5 @@
# Ownership and Borrowing
Learning resources:
- English: [Rust Book 4.1-4.4](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)
- 简体中文: [Rust语言圣经 - 所有权与借用](https://course.rs/basic/ownership/index.html)

View File

@ -0,0 +1,170 @@
# Ownership
1. 🌟🌟
```rust,editable
fn main() {
// use as many approaches as you can to make it work
let x = String::from("hello, world");
let y = x;
println!("{},{}",x,y);
}
```
2. 🌟🌟
```rust,editable
// Don't modify code in main!
fn main() {
let s1 = String::from("hello, world");
let s2 = take_ownership(s1);
println!("{}", s2);
}
// Only modify the code below!
fn take_ownership(s: String) {
println!("{}", s);
}
```
3. 🌟🌟
```rust,editable
fn main() {
let s = give_ownership();
println!("{}", s);
}
// Only modify the code below!
fn give_ownership() -> String {
let s = String::from("hello, world");
// convert String to Vec
let _s = s.into_bytes();
s
}
```
4. 🌟🌟
```rust,editable
// fix the error without removing code line
fn main() {
let s = String::from("hello, world");
print_str(s);
println!("{}", s);
}
fn print_str(s: String) {
println!("{}",s)
}
```
5. 🌟🌟
```rust, editable
// don't use clone ,use copy instead
fn main() {
let x = (1, 2, (), "hello".to_string());
let y = x.clone();
println!("{:?}, {:?}", x, y);
}
```
#### Mutability
Mutability can be changed when ownership is transferred.
6. 🌟
```rust,editable
fn main() {
let s = String::from("hello, ");
// modify this line only !
let s1 = s;
s1.push_str("world");
println!("Success!")
}
```
7. 🌟🌟🌟
```rust,editable
fn main() {
let x = Box::new(5);
let ... // implement this line, dont change other lines!
*y = 4;
assert_eq!(*x, 5);
println!("Success!")
}
```
### Partial move
Within the destructuring of a single variable, both by-move and by-reference pattern bindings can be used at the same time. Doing this will result in a partial move of the variable, which means that parts of the variable will be moved while other parts stay. In such a case, the parent variable cannot be used afterwards as a whole, however the parts that are only referenced (and not moved) can still be used.
#### Example
```rust,editable
fn main() {
#[derive(Debug)]
struct Person {
name: String,
age: Box<u8>,
}
let person = Person {
name: String::from("Alice"),
age: Box::new(20),
};
// `name` is moved out of person, but `age` is referenced
let Person { name, ref age } = person;
println!("The person's age is {}", age);
println!("The person's name is {}", name);
// Error! borrow of partially moved value: `person` partial move occurs
//println!("The person struct is {:?}", person);
// `person` cannot be used but `person.age` can be used as it is not moved
println!("The person's age from person struct is {}", person.age);
}
```
#### Exercises
8. 🌟
```rust,editable
fn main() {
let t = (String::from("hello"), String::from("world"));
let _s = t.0;
// modify this line only, don't use `_s`
println!("{:?}", t);
}
```
9. 🌟🌟
```rust,editable
fn main() {
let t = (String::from("hello"), String::from("world"));
// fill the blanks
let (__, __) = __;
println!("{:?}, {:?}, {:?}", s1, s2, t); // -> "hello", "world", ("hello", "world")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,6 @@
# Pattern Match
Learning resources:
- English: [Rust Book 18](https://doc.rust-lang.org/book/ch18-00-patterns.html)
- 简体中文: [Rust语言圣经 - 模式匹配](https://course.rs/basic/match-pattern/intro.html)

View File

@ -0,0 +1,210 @@
# match, if let
### match
1. 🌟🌟
```rust,editable
// fill the blanks
enum Direction {
East,
West,
North,
South,
}
fn main() {
let dire = Direction::South;
match dire {
Direction::East => println!("East"),
__ => { // matching South or North here
println!("South or North");
},
_ => println!(__),
};
}
```
2. 🌟🌟 match is an expression, so we can use it in assignments
```rust,editable
fn main() {
let boolean = true;
// fill the blank with an match expression:
//
// boolean = true => binary = 1
// boolean = false => binary = 0
let binary = __;
assert_eq!(binary, 1);
println!("Success!")
}
```
3. 🌟🌟 using match to get the data an enum variant holds
```rust,editable
// fill in the blanks
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msgs = [
Message::Quit,
Message::Move{x:1, y:3},
Message::ChangeColor(255,255,0)
];
for msg in msgs {
show_message(msg)
}
println!("Success!")
}
fn show_message(msg: Message) {
match msg {
__ => { // match Message::Move
assert_eq!(a, 1);
assert_eq!(b, 3);
},
Message::ChangeColor(_, g, b) => {
assert_eq!(g, __);
assert_eq!(b, __);
}
__ => println!("no data in these variants")
}
}
```
### matches!
[`matches!`](https://doc.rust-lang.org/stable/core/macro.matches.html) looks like `match`, but can do something different
4. 🌟🌟
```rust,editable
fn main() {
let alphabets = ['a', 'E', 'Z', '0', 'x', '9' , 'Y'];
// fill the blank with `matches!` to make the code work
for ab in alphabets {
assert!(__)
}
println!("Success!")
}
```
5. 🌟🌟
```rust,editable
enum MyEnum {
Foo,
Bar
}
fn main() {
let mut count = 0;
let v = vec![MyEnum::Foo,MyEnum::Bar,MyEnum::Foo];
for e in v {
if e == MyEnum::Foo { // fix the error with changing only this line
count += 1;
}
}
assert_eq!(count, 2);
println!("Success!")
}
```
### if let
For some cases, when matching enums, `match` is too heavy, we can use `if let` instead.
6. 🌟
```rust,editable
fn main() {
let o = Some(7);
// remove the whole `match` block, using `if let` instead
match o {
Some(i) => {
println!("This is a really long string and `{:?}`", i);
println!("Success!")
}
_ => {}
};
}
```
7. 🌟🌟
```rust,editable
// fill in the blank
enum Foo {
Bar(u8)
}
fn main() {
let a = Foo::Bar(1);
__ {
println!("foobar holds the value: {}", i);
println!("Success!")
}
}
```
8. 🌟🌟
```rust,editable
enum Foo {
Bar,
Baz,
Qux(u32)
}
fn main() {
let a = Foo::Qux(10);
// remove the codes below, using `match` instead
if let Foo::Bar = a {
println!("match foo::bar")
} else if let Foo::Baz = a {
println!("match foo::baz")
} else {
println!("match others")
}
}
```
### Shadowing
9. 🌟🌟
```rust,editable
// fix the errors in-place
fn main() {
let age = Some(30);
if let Some(age) = age { // create a new variable with the same name as previous `age`
assert_eq!(age, Some(30));
} // the new variable `age` goes out of scope here
match age {
// match can also introduce a new shadowed variable
Some(age) => println!("age is a new variable, it's value is {}",age),
_ => ()
}
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,119 @@
# Patterns
1. 🌟🌟 use `|` to match several values, use `..=` to match a inclusive range
```rust,editable
fn main() {}
fn match_number(n: i32) {
match n {
// match a single value
1 => println!("One!"),
// fill in the blank with `|`, DON'T use `..` ofr `..=`
__ => println!("match 2 -> 5"),
// match an inclusive range
6..=10 => {
println!("match 6 -> 10")
},
_ => {
println!("match 11 -> +infinite")
}
}
}
```
2. 🌟🌟🌟 The `@` operator lets us create a variable that holds a value at the same time we are testing that value to see whether it matches a pattern.
```rust,editable
struct Point {
x: i32,
y: i32,
}
fn main() {
// fill in the blank to let p match the second arm
let p = Point { x: __, y: __ };
match p {
Point { x, y: 0 } => println!("On the x axis at {}", x),
// second arm
Point { x: 0..=5, y: y@ (10 | 20 | 30) } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
}
}
```
3. 🌟🌟🌟
```rust,editable
// fix the errors
enum Message {
Hello { id: i32 },
}
fn main() {
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: 3..=7,
} => println!("Found an id in range [3, 7]: {}", id),
Message::Hello { id: newid@10 | 11 | 12 } => {
println!("Found an id in another range [10, 12]: {}", newid)
}
Message::Hello { id } => println!("Found some other id: {}", id),
}
}
```
4. 🌟🌟 A match guard is an additional if condition specified after the pattern in a match arm that must also match, along with the pattern matching, for that arm to be chosen.
```rust,editable
// fill in the blank to make the code work, `split` MUST be used
fn main() {
let num = Some(4);
let split = 5;
match num {
Some(x) __ => assert!(x < split),
Some(x) => assert!(x >= split),
None => (),
}
println!("Success!")
}
```
5. 🌟🌟 Ignoring remaining parts of the value with `..`
```rust,editable
// fill the blank to make the code work
fn main() {
let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);
match numbers {
__ => {
assert_eq!(first, 2);
assert_eq!(last, 2048);
}
}
println!("Success!")
}
```
6. 🌟🌟 Using pattern `&mut V` to match a mutable reference needs you to be very careful due to `V` being a value after matching
```rust,editable
// FIX the error with least changing
// DON'T remove any code line
fn main() {
let mut v = String::from("hello,");
let r = &mut v;
match r {
&mut value => value.push_str(" world!")
}
}
````
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

View File

@ -0,0 +1,5 @@
# Result and panic
Learning resources:
- English: [Rust Book 9.1, 9.2](https://doc.rust-lang.org/book/ch09-00-error-handling.html)
- 简体中文: [Rust语言圣经 - 返回值和错误处理](https://course.rs/basic/result-error/intro.html)

View File

@ -0,0 +1,111 @@
# panic!
The simplest error handling mechanism is to use `panic`. It just prints an error message and starts unwinding the stack, finally exit the current thread:
- if panic occured in `main` thread, then the program will be exited.
- if in spawned thread, then this thread will be terminated, but the program won't
1. 🌟🌟
```rust,editable
// FILL the blanks
fn drink(beverage: &str) {
if beverage == "lemonade" {
println!("Success!");
// IMPLEMENT the below code
__
}
println!("Excercise Failed if printing out this line!");
}
fn main() {
drink(__);
println!("Excercise Failed if printing out this line!");
}
```
## common panic cases
2. 🌟🌟
```rust,editable
// MAKE the code work by fixing all panics
fn main() {
assert_eq!("abc".as_bytes(), [96, 97, 98]);
let v = vec![1, 2, 3];
let ele = v[3];
// unwrap may panic when get return a None
let ele = v.get(3).unwrap();
// Sometimes, the compiler is unable to find the overflow errors for you in compile time ,so a panic will occur
let v = production_rate_per_hour(2);
// because of the same reason as above, we have to wrap it in a function to make the panic occur
divide(15, 0);
println!("Success!")
}
fn divide(x:u8, y:u8) {
println!("{}", x / y)
}
fn production_rate_per_hour(speed: u8) -> f64 {
let cph: u8 = 221;
match speed {
1..=4 => (speed * cph) as f64,
5..=8 => (speed * cph) as f64 * 0.9,
9..=10 => (speed * cph) as f64 * 0.77,
_ => 0 as f64,
}
}
pub fn working_items_per_minute(speed: u8) -> u32 {
(production_rate_per_hour(speed) / 60 as f64) as u32
}
```
### Detailed call stack
By default the stack unwinding will only give something like this:
```shell
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:4:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
Though there is the panic reason and code line showing here, but sometime we want to get more info about the call stack.
3. 🌟
```shell
## FILL in the blank to display the whole call stack
## Tips: you can find the clue in the default panic info
$ __ cargo run
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `[97, 98, 99]`,
right: `[96, 97, 98]`', src/main.rs:3:5
stack backtrace:
0: rust_begin_unwind
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/std/src/panicking.rs:498:5
1: core::panicking::panic_fmt
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/panicking.rs:116:14
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/panicking.rs:154:5
4: study_cargo::main
at ./src/main.rs:3:5
5: core::ops::function::FnOnce::call_once
at /rustc/9d1b2106e23b1abd32fce1f17267604a5102f57a/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```
### `unwinding` and `abort`
By default, when a `panic` occurs, the program starts *unwinding*, which means Rust walks back up the stack and cleans up the data from each function it encouters.
But this walk back and clean up is a lot of work. The alternative is to immediately abort the program without cleaning up.
If in your project you need to make the resulting binary as small as possible, you can switch from unwinding to aborting by adding below content to `Cargo.toml`:
```toml
[profile.release]
panic = 'abort'
```

View File

@ -0,0 +1,212 @@
# result and ?
`Result<T>` is an enum to describe possible errors. It has two variants:
- `Ok(T)`: a value T was found
- `Err(e)`: An error was found with a value `e`
In short words, the expected outcome is `Ok`, while the unexpected outcome is `Err`.
1. 🌟🌟
```rust,editable
// FILL in the blanks and FIX the errors
use std::num::ParseIntError;
fn multiply(n1_str: &str, n2_str: &str) -> __ {
let n1 = n1_str.parse::<i32>();
let n2 = n2_str.parse::<i32>();
Ok(n1.unwrap() * n2.unwrap())
}
fn main() {
let result = multiply("10", "2");
assert_eq!(result, __);
let result = multiply("t", "2");
assert_eq!(result.__, 8);
println!("Success!")
}
```
### ?
`?` is almost exactly equivalent to `unwrap`, but `?` returns instead of panic on `Err`.
2. 🌟🌟
```rust,editable
use std::num::ParseIntError;
// IMPLEMENT multiply with ?
// DON'T use unwrap here
fn multiply(n1_str: &str, n2_str: &str) -> __ {
}
fn main() {
assert_eq!(multiply("3", "4").unwrap(), 12);
println!("Success!")
}
```
3. 🌟🌟
```rust,editable
use std::fs::File;
use std::io::{self, Read};
fn read_file1() -> Result<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
// FILL in the blanks with one code line
// DON'T change any code else
fn read_file2() -> Result<String, io::Error> {
let mut s = String::new();
__;
Ok(s)
}
fn main() {
assert_eq!(read_file1().unwrap_err().to_string(), read_file2().unwrap_err().to_string());
println!("Success!")
}
```
### map & and_then
[map](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.map) and [and_then](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.and_then) are two common combinators for `Result<T, E>` (also for `Option<T>`).
4. 🌟🌟
```rust,editable
use std::num::ParseIntError;
// FILL in the blank in two ways: map, and then
fn add_two(n_str: &str) -> Result<i32, ParseIntError> {
n_str.parse::<i32>().__
}
fn main() {
assert_eq!(add_two("4").unwrap(), 6);
println!("Success!")
}
```
5. 🌟🌟🌟
```rust,editable
use std::num::ParseIntError;
// With the return type rewritten, we use pattern matching without `unwrap()`.
// But it's so Verbose..
fn multiply(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
match n1_str.parse::<i32>() {
Ok(n1) => {
match n2_str.parse::<i32>() {
Ok(n2) => {
Ok(n1 * n2)
},
Err(e) => Err(e),
}
},
Err(e) => Err(e),
}
}
// Rewriting `multiply` to make it succinct
// You should use BOTH of `and_then` and `map` here.
fn multiply1(n1_str: &str, n2_str: &str) -> Result<i32, ParseIntError> {
// IMPLEMENT...
}
fn print(result: Result<i32, ParseIntError>) {
match result {
Ok(n) => println!("n is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
// This still presents a reasonable answer.
let twenty = multiply1("10", "2");
print(twenty);
// The following now provides a much more helpful error message.
let tt = multiply("t", "2");
print(tt);
println!("Success!")
}
```
### Type alias
Using `std::result::Result<T, ParseIntError>` everywhere is verbose and tedious, we can use alias for this purpose.
At a module level, creating aliases can be particularly helpful. Errors found in the a specific module often has the same `Err` type, so a single alias can succinctly defined all associated `Results`. This is so useful even the `std` library even supplies one: [`io::Result`](https://doc.rust-lang.org/std/io/type.Result.html).
6. 🌟
```rust,editable
use std::num::ParseIntError;
// FILL in the blank
type __;
// Use the above alias to refer to our specific `Result` type.
fn multiply(first_number_str: &str, second_number_str: &str) -> Res<i32> {
first_number_str.parse::<i32>().and_then(|first_number| {
second_number_str.parse::<i32>().map(|second_number| first_number * second_number)
})
}
// Here, the alias again allows us to save some space.
fn print(result: Res<i32>) {
match result {
Ok(n) => println!("n is {}", n),
Err(e) => println!("Error: {}", e),
}
}
fn main() {
print(multiply("10", "2"));
print(multiply("t", "2"));
println!("Success!")
}
```
### Using Result in `fn main`
Typically `the` main function will look like this:
```rust
fn main() {
println!("Hello World!");
}
```
However `main` is also able to have a return type of `Result`. If an error occurs within the `main` function it will return an error code and print a debug representation of the error( Debug trait ).
The following example shows such a scenario:
```rust,editable
use std::num::ParseIntError;
fn main() -> Result<(), ParseIntError> {
let number_str = "10";
let number = match number_str.parse::<i32>() {
Ok(number) => number,
Err(e) => return Err(e),
};
println!("{}", number);
Ok(())
}
```

View File

@ -0,0 +1 @@
# Self referential

View File

@ -0,0 +1 @@
# Box

View File

@ -0,0 +1 @@
# Cell and RefCell

View File

@ -0,0 +1 @@
# Deref

View File

@ -0,0 +1 @@
# Drop

View File

@ -0,0 +1 @@
# Smart pointers

View File

@ -0,0 +1 @@
# Rc and Arc

1
en/src/std/String.md Normal file
View File

@ -0,0 +1 @@
# String

1
en/src/std/intro.md Normal file
View File

@ -0,0 +1 @@
# Stand Library todo

View File

@ -0,0 +1 @@
# Assertions

View File

@ -0,0 +1,3 @@
# Benchmark
https://doc.rust-lang.org/unstable-book/library-features/test.html

1
en/src/tests/intro.md Normal file
View File

@ -0,0 +1 @@
# Tests

View File

@ -0,0 +1 @@
# Unit and Integration

View File

@ -0,0 +1 @@
# Write Tests

1
en/src/threads/atomic.md Normal file
View File

@ -0,0 +1 @@
# Atomic

View File

@ -0,0 +1 @@
# Basic using

1
en/src/threads/intro.md Normal file
View File

@ -0,0 +1 @@
# Threads

View File

@ -0,0 +1 @@
# Message passing

View File

@ -0,0 +1 @@
# Send and Sync

1
en/src/threads/sync.md Normal file
View File

@ -0,0 +1 @@
# Sync

View File

@ -0,0 +1,105 @@
# Convert by `as`
Rust provides no implicit type conversion(coercion) between primitive types. But explicit type conversions can be performed using the `as` keyword.
1. 🌟
```rust,editable
// FIX the errors and FILL in the blank
// DON'T remove any code
fn main() {
let decimal = 97.123_f32;
let integer: __ = decimal as u8;
let c1: char = decimal as char;
let c2 = integer as char;
assert_eq!(integer, 'b' as u8);
println!("Success!")
}
```
2. 🌟🌟 By default, overflow will cause compile errors, but we can add an global annotation to suppress these errors.
```rust,editable
fn main() {
assert_eq!(u8::MAX, 255);
// the max of `u8` is 255 as shown above.
// so the below code will cause an overflow error: literal out of range for `u8`.
// PLEASE looking for clues within compile errors to FIX it.
// DON'T modify any code in main.
let v = 1000 as u8;
println!("Success!")
}
```
3. 🌟🌟 when casting any value to an unsigned type `T`, `T::MAX + 1` is added or subtracted until the value fits into the new type.
```rust,editable
fn main() {
assert_eq!(1000 as u16, __);
assert_eq!(1000 as u8, __);
// For positive numbers, this is the same as the modulus
println!("1000 mod 256 is : {}", 1000 % 256);
assert_eq!(-1_i8 as u8, __);
// Since Rust 1.45, the `as` keyword performs a *saturating cast*
// when casting from float to int. If the floating point value exceeds
// the upper bound or is less than the lower bound, the returned value
// will be equal to the bound crossed.
assert_eq!(300.1_f32 as u8, __);
assert_eq!(-100.1_f32 as u8, __);
// This behavior incurs a small runtime cost and can be avoided
// with unsafe methods, however the results might overflow and
// return **unsound values**. Use these methods wisely:
unsafe {
// 300.0 is 44
println!("300.0 is {}", 300.0_f32.to_int_unchecked::<u8>());
// -100.0 as u8 is 156
println!("-100.0 as u8 is {}", (-100.0_f32).to_int_unchecked::<u8>());
// nan as u8 is 0
println!("nan as u8 is {}", f32::NAN.to_int_unchecked::<u8>());
}
}
```
4. 🌟🌟🌟 Raw pointer can be converted to memory address (integer) and vice versa
```rust,editable
// FILL in the blanks
fn main() {
let mut values: [i32; 2] = [1, 2];
let p1: *mut i32 = values.as_mut_ptr();
let first_address: usize = p1 __;
let second_address = first_address + 4; // 4 == std::mem::size_of::<i32>()
let p2: *mut i32 = second_address __; // p2 points to the 2nd element in values
unsafe {
// add one to the second element
__
}
assert_eq!(values[1], 3);
println!("Success!")
}
```
5. 🌟🌟🌟
```rust,editable
fn main() {
let arr :[u64; 13] = [0; 13];
assert_eq!(std::mem::size_of_val(&arr), 8 * 13);
let a: *const [u64] = &arr;
let b = a as *const [u8];
unsafe {
assert_eq!(std::mem::size_of_val(&*b), __)
}
println!("Success!")
}
```

View File

@ -0,0 +1,171 @@
# From/Into
The `From` trait allows for a type to define how to create itself from another type, hence providing a very simple mechanism for converting between several types.
The `From` and `Into` traits are inherently linked, and this is actually part of its implementation. It means if we write something like this: `impl From<T> for U`, then we can use
`let u: U = U::from(T)` or `let u:U = T.into()`.
The `Into` trait is simply the reciprocal of the `From` trait. That is, if you have implemented the `From` trait for your type, then the `Into` trait will be automatically implemented for the same type.
Using the `Into` trait will typically require the type annotations as the compiler is unable to determine this most of the time.
For example we can easily convert `&str` into `String` :
```rust
fn main() {
let my_str = "hello";
// three conversions below all depends on the fact: String implements From<&str>:
let string1 = String::from(my_str);
let string2 = my_str.to_string();
// explict type annotation is required here
let string3: String = my_str.into();
}
```
because the standard library has already implemented this for us : `impl From<&'_ str> for String` .
Some implementations of `From` trait can be found [here](https://doc.rust-lang.org/stable/std/convert/trait.From.html#implementors).
1. 🌟🌟🌟
```rust,editable
fn main() {
// impl From<bool> for i32
let i1:i32 = false.into();
let i2:i32 = i32::from(false);
assert_eq!(i1, i2);
assert_eq!(i1, 0);
// FIX the error in two ways
// 1. impl From<char> for ? , maybe you should check the docs mentiond above to find the answer
// 2. a keyword from the last chapter
let i3: i32 = 'a'.into();
// FIX the error in two ways
let s: String = 'a' as String;
println!("Success!")
}
```
### Implement `From` for custom types
2. 🌟🌟
```rust,editable
// From is now included in `std::prelude`, so there is no need to introduce it into the current scope
// use std::convert::From;
#[derive(Debug)]
struct Number {
value: i32,
}
impl From<i32> for Number {
// IMPLEMENT `from` method
}
// FILL in the blanks
fn main() {
let num = __(30);
assert_eq!(num.value, 30);
let num: Number = __;
assert_eq!(num.value, 30);
println!("Success!")
}
```
3. 🌟🌟🌟 When performing error handling it is often useful to implement `From` trait for our own error type. Then we can use `?` to automatically convert the underlying error type to our own error type.
```rust,editable
use std::fs;
use std::io;
use std::num;
enum CliError {
IoError(io::Error),
ParseError(num::ParseIntError),
}
impl From<io::Error> for CliError {
// IMPLEMENT from method
}
impl From<num::ParseIntError> for CliError {
// IMPLEMENT from method
}
fn open_and_parse_file(file_name: &str) -> Result<i32, CliError> {
// ? automatically converts io::Error to CliError
let contents = fs::read_to_string(&file_name)?;
// num::ParseIntError -> CliError
let num: i32 = contents.trim().parse()?;
Ok(num)
}
fn main() {
println!("Success!")
}
```
### TryFrom/TryInto
Similar to `From` and `Into`, `TryFrom` and `TryInto` are generic traits for converting between types.
Unlike `From/Into`, `TryFrom` and `TryInto` are used for fallible conversions and return a `Result` instead of a plain value.
4. 🌟🌟
```rust,editable
// TryFrom and TryInto are included in `std::prelude`, so there is no need to introduce it into the current scope
// use std::convert::TryInto;
fn main() {
let n: i16 = 256;
// Into trait has a method `into`,
// hence TryInto has a method ?
let n: u8 = match n.__() {
Ok(n) => n,
Err(e) => {
println!("there is an error when converting: {:?}, but we catch it", e.to_string());
0
}
};
assert_eq!(n, __);
println!("Success!")
}
```
5. 🌟🌟🌟
```rust,editable
#[derive(Debug, PartialEq)]
struct EvenNum(i32);
impl TryFrom<i32> for EvenNum {
type Error = ();
// IMPLEMENT `try_from`
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value % 2 == 0 {
Ok(EvenNum(value))
} else {
Err(())
}
}
}
fn main() {
assert_eq!(EvenNum::try_from(8), Ok(EvenNum(8)));
assert_eq!(EvenNum::try_from(5), Err(()));
// FILL in the blanks
let result: Result<EvenNum, ()> = 8i32.try_into();
assert_eq!(result, __);
let result: Result<EvenNum, ()> = 5i32.try_into();
assert_eq!(result, __);
println!("Success!")
}
```

View File

@ -0,0 +1,5 @@
# Ownership and Borrowing
Learning resources:
- English: [Standary library](https://std.rs)
- 简体中文: [Rust语言圣经 - 所有权与借用](https://course.rs/basic/converse.html)

View File

@ -0,0 +1,164 @@
# Others
### Convert any type to String
To convert any type to `String`, you can simply the `ToString` trait for that type. Rather than doing that directly, you should implement the `fmt::Display` trait which will automatically provides `ToString` and also allows you to print the type with `println!`.
1. 🌟🌟
```rust,editable
use std::fmt;
struct Point {
x: i32,
y: i32,
}
impl fmt::Display for Point {
// IMPLEMENT fmt method
}
fn main() {
let origin = Point { x: 0, y: 0 };
// FILL in the blanks
assert_eq!(origin.__, "The point is (0, 0)");
assert_eq!(format!(__), "The point is (0, 0)");
println!("Success!")
}
```
### Parse a String
2. 🌟🌟🌟 We can use `parse` method to convert a `String` into a `i32` number, this is becuase `FromStr` is implemented for `i32` type in standard library: `impl FromStr for i32`
```rust,editable
// To use `from_str` method, you needs to introduce this trait into the current scope.
use std::str::FromStr;
fn main() {
let parsed: i32 = "5".__.unwrap();
let turbo_parsed = "10".__.unwrap();
let from_str = __.unwrap();
let sum = parsed + turbo_parsed + from_str;
assert_eq!(sum, 35);
println!("Success!")
}
```
3. 🌟🌟 We can also implement the `FromStr` trait for our custom types
```rust,editable
use std::str::FromStr;
use std::num::ParseIntError;
#[derive(Debug, PartialEq)]
struct Point {
x: i32,
y: i32
}
impl FromStr for Point {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' )
.split(',')
.collect();
let x_fromstr = coords[0].parse::<i32>()?;
let y_fromstr = coords[1].parse::<i32>()?;
Ok(Point { x: x_fromstr, y: y_fromstr })
}
}
fn main() {
// FILL in the blanks in two ways
// DON'T change code anywhere else
let p = __;
assert_eq!(p.unwrap(), Point{ x: 3, y: 4} );
println!("Success!")
}
```
### Deref
You can find all the examples and exercises of the `Deref` trait [here](https://practice.rs/smart-pointers/deref.html).
### transmute
`std::mem::transmute` is a **unsafe function** can be used to reinterprets the bits of a value of one type as another type. Both of the orginal and the result types must have the same size and neither of them can be invalid.
`transmute` is semantically equivalent to a bitwise move of one type into another. It copies the bits from the source value into the destination value, then forgets the original, seems equivalent to C's `memcpy` under the hood.
So, **`transmute` is incredibly unsafe !** The caller has to ensure all the safes himself!
#### Examples
1. `transmute` can be used to turn a pointer into a function pointer, this is not portable on machines where function pointer and data pointer have different sizes.
```rust,editable
fn foo() -> i32 {
0
}
fn main() {
let pointer = foo as *const ();
let function = unsafe {
std::mem::transmute::<*const (), fn() -> i32>(pointer)
assert_eq!(function(), 0);
}
```
2. Extending a lifetime or shortening the lifetime of an invariant is an advanced usage of `transmute`, yeah, **very unsafe Rust!**.
```rust,editable
struct R<'a>(&'a i32);
unsafe fn extend_lifetime<'b>(r: R<'b>) -> R<'static> {
std::mem::transmute::<R<'b>, R<'static>>(r)
}
unsafe fn shorten_invariant_lifetime<'b, 'c>(r: &'b mut R<'static>)
-> &'b mut R<'c> {
std::mem::transmute::<&'b mut R<'static>, &'b mut R<'c>>(r)
}
```
3. Rather than using `transmute`, you can use some alternatives instead.
```rust,editable
fn main() {
/*Turning raw bytes(&[u8]) to u32, f64, etc.: */
let raw_bytes = [0x78, 0x56, 0x34, 0x12];
let num = unsafe { std::mem::transmute::<[u8; 4], u32>(raw_bytes) };
// use `u32::from_ne_bytes` instead
let num = u32::from_ne_bytes(raw_bytes);
// or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness
let num = u32::from_le_bytes(raw_bytes);
assert_eq!(num, 0x12345678);
let num = u32::from_be_bytes(raw_bytes);
assert_eq!(num, 0x78563412);
/*Turning a pointer into a usize: */
let ptr = &0;
let ptr_num_transmute = unsafe { std::mem::transmute::<&i32, usize>(ptr) };
// Use an `as` cast instead
let ptr_num_cast = ptr as *const i32 as usize;
/*Turning an &mut T into an &mut U: */
let ptr = &mut 0;
let val_transmuted = unsafe { std::mem::transmute::<&mut i32, &mut u32>(ptr) };
// Now, put together `as` and reborrowing - note the chaining of `as`
// `as` is not transitive
let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) };
/*Turning an &str into a &[u8]: */
// this is not a good way to do this.
let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") };
assert_eq!(slice, &[82, 117, 115, 116]);
// You could use `str::as_bytes`
let slice = "Rust".as_bytes();
assert_eq!(slice, &[82, 117, 115, 116]);
// Or, just use a byte string, if you have control over the string
// literal
assert_eq!(b"Rust", &[82, 117, 115, 116]);
}
```

441
en/src/unsafe/inline-asm.md Normal file
View File

@ -0,0 +1,441 @@
# Inline assembly
Rust provides support for inline assembly via the `asm!` macro.
It can be used to embed handwritten assembly in the assembly output generated by the compiler.
Generally this should not be necessary, but might be where the required performance or timing
cannot be otherwise achieved. Accessing low level hardware primitives, e.g. in kernel code, may also demand this functionality.
> **Note**: the examples here are given in x86/x86-64 assembly, but other architectures are also supported.
Inline assembly is currently supported on the following architectures:
- x86 and x86-64
- ARM
- AArch64
- RISC-V
## Basic usage
Let us start with the simplest possible example:
```rust
use std::arch::asm;
unsafe {
asm!("nop");
}
```
This will insert a NOP (no operation) instruction into the assembly generated by the compiler.
Note that all `asm!` invocations have to be inside an `unsafe` block, as they could insert
arbitrary instructions and break various invariants. The instructions to be inserted are listed
in the first argument of the `asm!` macro as a string literal.
## Inputs and outputs
Now inserting an instruction that does nothing is rather boring. Let us do something that
actually acts on data:
```rust
use std::arch::asm;
let x: u64;
unsafe {
asm!("mov {}, 5", out(reg) x);
}
assert_eq!(x, 5);
```
This will write the value `5` into the `u64` variable `x`.
You can see that the string literal we use to specify instructions is actually a template string.
It is governed by the same rules as Rust [format strings][format-syntax].
The arguments that are inserted into the template however look a bit different than you may
be familiar with. First we need to specify if the variable is an input or an output of the
inline assembly. In this case it is an output. We declared this by writing `out`.
We also need to specify in what kind of register the assembly expects the variable.
In this case we put it in an arbitrary general purpose register by specifying `reg`.
The compiler will choose an appropriate register to insert into
the template and will read the variable from there after the inline assembly finishes executing.
[format-syntax]: https://doc.rust-lang.org/std/fmt/#syntax
Let us see another example that also uses an input:
```rust
use std::arch::asm;
let i: u64 = 3;
let o: u64;
unsafe {
asm!(
"mov {0}, {1}",
"add {0}, 5",
out(reg) o,
in(reg) i,
);
}
assert_eq!(o, 8);
```
This will add `5` to the input in variable `i` and write the result to variable `o`.
The particular way this assembly does this is first copying the value from `i` to the output,
and then adding `5` to it.
The example shows a few things:
First, we can see that `asm!` allows multiple template string arguments; each
one is treated as a separate line of assembly code, as if they were all joined
together with newlines between them. This makes it easy to format assembly
code.
Second, we can see that inputs are declared by writing `in` instead of `out`.
Third, we can see that we can specify an argument number, or name as in any format string.
For inline assembly templates this is particularly useful as arguments are often used more than once.
For more complex inline assembly using this facility is generally recommended, as it improves
readability, and allows reordering instructions without changing the argument order.
We can further refine the above example to avoid the `mov` instruction:
```rust
use std::arch::asm;
let mut x: u64 = 3;
unsafe {
asm!("add {0}, 5", inout(reg) x);
}
assert_eq!(x, 8);
```
We can see that `inout` is used to specify an argument that is both input and output.
This is different from specifying an input and output separately in that it is guaranteed to assign both to the same register.
It is also possible to specify different variables for the input and output parts of an `inout` operand:
```rust
use std::arch::asm;
let x: u64 = 3;
let y: u64;
unsafe {
asm!("add {0}, 5", inout(reg) x => y);
}
assert_eq!(y, 8);
```
## Late output operands
The Rust compiler is conservative with its allocation of operands. It is assumed that an `out`
can be written at any time, and can therefore not share its location with any other argument.
However, to guarantee optimal performance it is important to use as few registers as possible,
so they won't have to be saved and reloaded around the inline assembly block.
To achieve this Rust provides a `lateout` specifier. This can be used on any output that is
written only after all inputs have been consumed.
There is also a `inlateout` variant of this specifier.
Here is an example where `inlateout` *cannot* be used:
```rust
use std::arch::asm;
let mut a: u64 = 4;
let b: u64 = 4;
let c: u64 = 4;
unsafe {
asm!(
"add {0}, {1}",
"add {0}, {2}",
inout(reg) a,
in(reg) b,
in(reg) c,
);
}
assert_eq!(a, 12);
```
Here the compiler is free to allocate the same register for inputs `b` and `c` since it knows they have the same value. However it must allocate a separate register for `a` since it uses `inout` and not `inlateout`. If `inlateout` was used, then `a` and `c` could be allocated to the same register, in which case the first instruction to overwrite the value of `c` and cause the assembly code to produce the wrong result.
However the following example can use `inlateout` since the output is only modified after all input registers have been read:
```rust
use std::arch::asm;
let mut a: u64 = 4;
let b: u64 = 4;
unsafe {
asm!("add {0}, {1}", inlateout(reg) a, in(reg) b);
}
assert_eq!(a, 8);
```
As you can see, this assembly fragment will still work correctly if `a` and `b` are assigned to the same register.
## Explicit register operands
Some instructions require that the operands be in a specific register.
Therefore, Rust inline assembly provides some more specific constraint specifiers.
While `reg` is generally available on any architecture, explicit registers are highly architecture specific. E.g. for x86 the general purpose registers `eax`, `ebx`, `ecx`, `edx`, `ebp`, `esi`, and `edi` among others can be addressed by their name.
```rust,no_run
use std::arch::asm;
let cmd = 0xd1;
unsafe {
asm!("out 0x64, eax", in("eax") cmd);
}
```
In this example we call the `out` instruction to output the content of the `cmd` variable to port `0x64`. Since the `out` instruction only accepts `eax` (and its sub registers) as operand we had to use the `eax` constraint specifier.
> **Note**: unlike other operand types, explicit register operands cannot be used in the template string: you can't use `{}` and should write the register name directly instead. Also, they must appear at the end of the operand list after all other operand types.
Consider this example which uses the x86 `mul` instruction:
```rust
use std::arch::asm;
fn mul(a: u64, b: u64) -> u128 {
let lo: u64;
let hi: u64;
unsafe {
asm!(
// The x86 mul instruction takes rax as an implicit input and writes
// the 128-bit result of the multiplication to rax:rdx.
"mul {}",
in(reg) a,
inlateout("rax") b => lo,
lateout("rdx") hi
);
}
((hi as u128) << 64) + lo as u128
}
```
This uses the `mul` instruction to multiply two 64-bit inputs with a 128-bit result.
The only explicit operand is a register, that we fill from the variable `a`.
The second operand is implicit, and must be the `rax` register, which we fill from the variable `b`.
The lower 64 bits of the result are stored in `rax` from which we fill the variable `lo`.
The higher 64 bits are stored in `rdx` from which we fill the variable `hi`.
## Clobbered registers
In many cases inline assembly will modify state that is not needed as an output.
Usually this is either because we have to use a scratch register in the assembly or because instructions modify state that we don't need to further examine.
This state is generally referred to as being "clobbered".
We need to tell the compiler about this since it may need to save and restore this state around the inline assembly block.
```rust
use core::arch::asm;
fn main() {
// three entries of four bytes each
let mut name_buf = [0_u8; 12];
// String is stored as ascii in ebx, edx, ecx in order
// Because ebx is reserved, we get a scratch register and move from
// ebx into it in the asm. The asm needs to preserve the value of
// that register though, so it is pushed and popped around the main asm
// (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx)
unsafe {
asm!(
"push rbx",
"cpuid",
"mov [{0}], ebx",
"mov [{0} + 4], edx",
"mov [{0} + 8], ecx",
"pop rbx",
// We use a pointer to an array for storing the values to simplify
// the Rust code at the cost of a couple more asm instructions
// This is more explicit with how the asm works however, as opposed
// to explicit register outputs such as `out("ecx") val`
// The *pointer itself* is only an input even though it's written behind
in(reg) name_buf.as_mut_ptr(),
// select cpuid 0, also specify eax as clobbered
inout("eax") 0 => _,
// cpuid clobbers these registers too
out("ecx") _,
out("edx") _,
);
}
let name = core::str::from_utf8(&name_buf).unwrap();
println!("CPU Manufacturer ID: {}", name);
}
```
In the example above we use the `cpuid` instruction to read the CPU manufacturer ID.
This instruction writes to `eax` with the maximum supported `cpuid` argument and `ebx`, `esx`, and `ecx` with the CPU manufacturer ID as ASCII bytes in that order.
Even though `eax` is never read we still need to tell the compiler that the register has been modified so that the compiler can save any values that were in these registers before the asm. This is done by declaring it as an output but with `_` instead of a variable name, which indicates that the output value is to be discarded.
This code also works around the limitation that `ebx` is a reserved register by LLVM. That means that LLVM assumes that it has full control over the register and it must be restored to its original state before exiting the asm block, so it cannot be used as an output. To work around this we save the register via `push`, read from `ebx` inside the asm block into a temporary register allocated with `out(reg)` and then restoring `ebx` to its original state via `pop`. The `push` and `pop` use the full 64-bit `rbx` version of the register to ensure that the entire register is saved. On 32 bit targets the code would instead use `ebx` in the `push`/`pop`.
This can also be used with a general register class (e.g. `reg`) to obtain a scratch register for use inside the asm code:
```rust
use std::arch::asm;
// Multiply x by 6 using shifts and adds
let mut x: u64 = 4;
unsafe {
asm!(
"mov {tmp}, {x}",
"shl {tmp}, 1",
"shl {x}, 2",
"add {x}, {tmp}",
x = inout(reg) x,
tmp = out(reg) _,
);
}
assert_eq!(x, 4 * 6);
```
## Symbol operands and ABI clobbers
By default, `asm!` assumes that any register not specified as an output will have its contents preserved by the assembly code. The [`clobber_abi`] argument to `asm!` tells the compiler to automatically insert the necessary clobber operands according to the given calling convention ABI: any register which is not fully preserved in that ABI will be treated as clobbered. Multiple `clobber_abi` arguments may be provided and all clobbers from all specified ABIs will be inserted.
[`clobber_abi`]: ../../reference/inline-assembly.html#abi-clobbers
```rust
use std::arch::asm;
extern "C" fn foo(arg: i32) -> i32 {
println!("arg = {}", arg);
arg * 2
}
fn call_foo(arg: i32) -> i32 {
unsafe {
let result;
asm!(
"call *{}",
// Function pointer to call
in(reg) foo,
// 1st argument in rdi
in("rdi") arg,
// Return value in rax
out("rax") result,
// Mark all registers which are not preserved by the "C" calling
// convention as clobbered.
clobber_abi("C"),
);
result
}
}
```
## Register template modifiers
In some cases, fine control is needed over the way a register name is formatted when inserted into the template string. This is needed when an architecture's assembly language has several names for the same register, each typically being a "view" over a subset of the register (e.g. the low 32 bits of a 64-bit register).
By default the compiler will always choose the name that refers to the full register size (e.g. `rax` on x86-64, `eax` on x86, etc).
This default can be overriden by using modifiers on the template string operands, just like you would with format strings:
```rust
use std::arch::asm;
let mut x: u16 = 0xab;
unsafe {
asm!("mov {0:h}, {0:l}", inout(reg_abcd) x);
}
assert_eq!(x, 0xabab);
```
In this example, we use the `reg_abcd` register class to restrict the register allocator to the 4 legacy x86 registers (`ax`, `bx`, `cx`, `dx`) of which the first two bytes can be addressed independently.
Let us assume that the register allocator has chosen to allocate `x` in the `ax` register.
The `h` modifier will emit the register name for the high byte of that register and the `l` modifier will emit the register name for the low byte. The asm code will therefore be expanded as `mov ah, al` which copies the low byte of the value into the high byte.
If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
## Memory address operands
Sometimes assembly instructions require operands passed via memory addresses/memory locations.
You have to manually use the memory address syntax specified by the target architecture.
For example, on x86/x86_64 using Intel assembly syntax, you should wrap inputs/outputs in `[]` to indicate they are memory operands:
```rust
use std::arch::asm;
fn load_fpu_control_word(control: u16) {
unsafe {
asm!("fldcw [{}]", in(reg) &control, options(nostack));
}
}
```
## Labels
Any reuse of a named label, local or otherwise, can result in an assembler or linker error or may cause other strange behavior. Reuse of a named label can happen in a variety of ways including:
- explicitly: using a label more than once in one `asm!` block, or multiple times across blocks.
- implicitly via inlining: the compiler is allowed to instantiate multiple copies of an `asm!` block, for example when the function containing it is inlined in multiple places.
- implicitly via LTO: LTO can cause code from *other crates* to be placed in the same codegen unit, and so could bring in arbitrary labels.
As a consequence, you should only use GNU assembler **numeric** [local labels] inside inline assembly code. Defining symbols in assembly code may lead to assembler and/or linker errors due to duplicate symbol definitions.
Moreover, on x86 when using the default Intel syntax, due to [an LLVM bug], you shouldn't use labels exclusively made of `0` and `1` digits, e.g. `0`, `11` or `101010`, as they may end up being interpreted as binary values. Using `options(att_syntax)` will avoid any ambiguity, but that affects the syntax of the _entire_ `asm!` block. (See [Options](#options), below, for more on `options`.)
```rust
use std::arch::asm;
let mut a = 0;
unsafe {
asm!(
"mov {0}, 10",
"2:",
"sub {0}, 1",
"cmp {0}, 3",
"jle 2f",
"jmp 2b",
"2:",
"add {0}, 2",
out(reg) a
);
}
assert_eq!(a, 5);
```
This will decrement the `{0}` register value from 10 to 3, then add 2 and store it in `a`.
This example shows a few things:
- First, that the same number can be used as a label multiple times in the same inline block.
- Second, that when a numeric label is used as a reference (as an instruction operand, for example), the suffixes “b” (“backward”) or ”f” (“forward”) should be added to the numeric label. It will then refer to the nearest label defined by this number in this direction.
[local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
[an LLVM bug]: https://bugs.llvm.org/show_bug.cgi?id=36144
## Options
By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However, in many cases it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
Let's take our previous example of an `add` instruction:
```rust
use std::arch::asm;
let mut a: u64 = 4;
let b: u64 = 4;
unsafe {
asm!(
"add {0}, {1}",
inlateout(reg) a, in(reg) b,
options(pure, nomem, nostack),
);
}
assert_eq!(a, 8);
```
Options can be provided as an optional final argument to the `asm!` macro. We specified three options here:
- `pure` means that the asm code has no observable side effects and that its output depends only on its inputs. This allows the compiler optimizer to call the inline asm fewer times or even eliminate it entirely.
- `nomem` means that the asm code does not read or write to memory. By default the compiler will assume that inline assembly can read or write any memory address that is accessible to it (e.g. through a pointer passed as an operand, or a global).
- `nostack` means that the asm code does not push any data onto the stack. This allows the compiler to use optimizations such as the stack red zone on x86-64 to avoid stack pointer adjustments.
These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed.
See the [reference](../../reference/inline-assembly.html) for the full list of available options and their effects.

1
en/src/unsafe/intro.md Normal file
View File

@ -0,0 +1 @@
# Unsafe todo

158
en/src/variables.md Normal file
View File

@ -0,0 +1,158 @@
# Variables
### Binding and mutablity
1. 🌟 A variable can be used only if it has been initialized.
```rust,editable
// fix the error below with least modifying
fn main() {
let x: i32; // uninitialized but using, ERROR !
let y: i32; // uninitialized but also unusing, only warning
assert_eq!(x, 5);
println!("Success!")
}
```
2. 🌟 Use `mut` to mark a variable as mutable.
```rust,editable
// fill the blanks in code to make it compile
fn main() {
let __ = 1;
__ += 2;
assert_eq!(x, 3);
println!("Success!")
}
```
### Scope
A scope is the range within the program for which the item is valid.
3. 🌟
```rust,editable
// fix the error below with least modifying
fn main() {
let x: i32 = 10;
{
let y: i32 = 5;
println!("The value of x is {} and value of y is {}", x, y);
}
println!("The value of x is {} and value of y is {}", x, y);
}
```
4. 🌟🌟
```rust,editable
// fix the error with using of define_x
fn main() {
println!("{}, world", x);
}
fn define_x() {
let x = "hello";
}
```
### Shadowing
You can declare a new variable with the same name as a previous variable, here we can say **the first one is shadowed by the second one.
5. 🌟🌟
```rust,editable
// only modify `assert_eq!` to make the `println!` work(print `42` in terminal)
fn main() {
let x: i32 = 5;
{
let x = 12;
assert_eq!(x, 5);
}
assert_eq!(x, 12);
let x = 42;
println!("{}", x); // Prints "42".
}
```
6. 🌟🌟
```rust,editable
// remove a line in code to make it compile
fn main() {
let mut x: i32 = 1;
x = 7;
// shadowing and re-binding
let x = x;
x += 3;
let y = 4;
// shadowing
let y = "I can also be bound to text!";
println!("Success!")
}
```
### Unused varibles
1. fix the warning below with :
- 🌟 only one solution
- 🌟🌟 two distinct solutions
> Note: none of the solutions is to remove the line `let x = 1`
```rust,editable
fn main() {
let x = 1;
}
// warning: unused variable: `x`
```
### Destructuring
8. 🌟🌟 We can use a pattern with `let` to destructure a tuple to separate variables.
> Tips: you can use Shadowing or Mutability
```rust,editable
// fix the error below with least modifying
fn main() {
let (x, y) = (1, 2);
x += 2;
assert_eq!(x, 3);
assert_eq!(y, 2);
println!("Success!")
}
```
### Destructuring assignments
Introducing in Rust 1.59: You can now use tuple, slice, and struct patterns as the left-hand side of an assignment.
9. 🌟🌟
> Note: the feature `Destructuring assignments` need 1.59 or higher Rust version
```rust,editable
fn main() {
let (x, y);
(x,..) = (3, 4);
[.., y] = [1, 2];
// fill the blank to make the code work
assert_eq!([x,y], __);
println!("Success!")
}
```
> You can find the solutions [here](https://github.com/sunface/rust-by-practice)(under the solutions path), but only use it when you need it

1
en/src/weak.md Normal file
View File

@ -0,0 +1 @@
# Weak and Circle reference

46
en/src/why-exercise.md Normal file
View File

@ -0,0 +1,46 @@
<div align="center">
<img height="150" src="https://github.com/sunface/rust-by-practice/blob/master/assets/logo.png?raw=true">
</div>
<p align="center">Practice Rust with challenging examples, exercises and projects</p>
<div align="center">
[![Stars Count](https://img.shields.io/github/stars/sunface/rust-by-practice?style=flat)](https://github.com/sunface/rust-by-practice/stargazers) [![Forks Count](https://img.shields.io/github/forks/sunface/rust-by-practice.svg?style=flat)](https://github.com/naaive/orange/network/members)
[![LICENSE](https://img.shields.io/badge/license-mit-green?style=flat)](https://github.com/sunface/rust-by-practice/blob/master/LICENSE)
</div>
This book was designed for easily diving into and get skilled with Rust, and it's very easy to use: All you need to do is to make each exercise compile without ERRORS and Panics !
## Reading online
- [English](https://practice.rs)
- [简体中文](https://zh.practice.rs)
## Running locally
We use [mdbook](https://rust-lang.github.io/mdBook/) building our exercises. You can run locally with below steps:
```shell
$ cargo install mdbook
$ cd rust-by-practice && mdbook serve
```
## Features
Part of our examples and exercises are borrowed from [Rust By Example](https://github.com/rust-lang/rust-by-example), thanks for your great works!
Although they are so awesome, we have our own secret weapons :)
- There are three parts in each chapter: examples, exercises and practices
- Besides examples, we have `a lot of exercises`, you can Read, Edit and Run them ONLINE
- Covering nearly all aspects of Rust, such as async/await, threads, sync primitives, optimizing, standard libraries, tool chain, data structures and algorithms etc.
- Every exercise has its own solutions
- The overall difficulties are a bit higher and from easy to super hard: easy 🌟 medium 🌟🌟 hard 🌟🌟🌟 super hard 🌟🌟🌟🌟
**What we want to do is fill in the gap between learning and getting started with real projects.**