mirror of
https://github.com/sunface/rust-by-practice.git
synced 2025-06-23 04:29:41 +00:00
Merge branch 'master' into patch-1
This commit is contained in:
BIN
en/assets/header.jpg
Normal file
BIN
en/assets/header.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
en/assets/header1.png
Normal file
BIN
en/assets/header1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
@ -4,7 +4,7 @@
|
||||
1. 🌟
|
||||
```rust, editable
|
||||
|
||||
// make it work
|
||||
// Make it work
|
||||
use std::mem::size_of_val;
|
||||
fn main() {
|
||||
let c1 = 'a';
|
||||
@ -13,14 +13,14 @@ fn main() {
|
||||
let c2 = '中';
|
||||
assert_eq!(size_of_val(&c2),3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟
|
||||
```rust, editable
|
||||
|
||||
// make it work
|
||||
// Make it work
|
||||
fn main() {
|
||||
let c1 = "中";
|
||||
print_char(c1);
|
||||
@ -35,13 +35,13 @@ fn print_char(c : char) {
|
||||
3. 🌟
|
||||
```rust, editable
|
||||
|
||||
// make println! work
|
||||
// Make println! work
|
||||
fn main() {
|
||||
let _f: bool = false;
|
||||
|
||||
let t = true;
|
||||
if !t {
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -49,13 +49,13 @@ fn main() {
|
||||
4. 🌟
|
||||
```rust, editable
|
||||
|
||||
// make it work
|
||||
// Make it work
|
||||
fn main() {
|
||||
let f = true;
|
||||
let t = true && false;
|
||||
assert_eq!(t, f);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -64,36 +64,36 @@ fn main() {
|
||||
5. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// make it work, don't modify `implicitly_ret_unit` !
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn implicitly_ret_unit() {
|
||||
println!("I will return a ()")
|
||||
println!("I will return a ()");
|
||||
}
|
||||
|
||||
// don't use this one
|
||||
// Don't use this one
|
||||
fn explicitly_ret_unit() -> () {
|
||||
println!("I will return a ()")
|
||||
println!("I will return a ()");
|
||||
}
|
||||
```
|
||||
|
||||
6. 🌟🌟 what's the size of the unit type?
|
||||
6. 🌟🌟 What's the size of the unit type?
|
||||
```rust,editable
|
||||
|
||||
// modify `4` in assert to make it work
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -3,13 +3,13 @@
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// don't modify the following two lines!
|
||||
// Don't modify the following two lines!
|
||||
let (x, y) = (1, 2);
|
||||
let s = sum(x, y);
|
||||
|
||||
assert_eq!(s, 3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn sum(x, y: i32) {
|
||||
@ -24,9 +24,9 @@ fn main() {
|
||||
print();
|
||||
}
|
||||
|
||||
// replace i32 with another type
|
||||
// Replace i32 with another type
|
||||
fn print() -> i32 {
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -34,16 +34,16 @@ fn print() -> i32 {
|
||||
3. 🌟🌟🌟
|
||||
|
||||
```rust,editable
|
||||
// solve it in two ways
|
||||
// Solve it in two ways
|
||||
// DON'T let `println!` works
|
||||
fn main() {
|
||||
never_return();
|
||||
|
||||
println!("Failed!")
|
||||
println!("Failed!");
|
||||
}
|
||||
|
||||
fn never_return() -> ! {
|
||||
// implement this function, don't modify the fn signatures
|
||||
// Implement this function, don't modify the fn signatures
|
||||
|
||||
}
|
||||
```
|
||||
@ -90,11 +90,11 @@ fn main() {
|
||||
// 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")
|
||||
panic!("we have no value for `false`, but we can panic");
|
||||
}
|
||||
};
|
||||
|
||||
println!("Excercise Failed if printing out this line!");
|
||||
println!("Exercise Failed if printing out this line!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -4,49 +4,49 @@
|
||||
|
||||
1. 🌟
|
||||
|
||||
> Tips: If we don't explicitly give one type to a varible, then the compiler will infer one for us
|
||||
> Tips: If we don't explicitly assign a type to a variable, then the compiler will infer one for us.
|
||||
|
||||
```rust,editable
|
||||
|
||||
// remove something to make it work
|
||||
// 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 ?
|
||||
let z = 10; // Type of z ?
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
fn main() {
|
||||
let v: u16 = 38_u8 as __;
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
3. 🌟🌟🌟
|
||||
|
||||
> Tips: If we don't explicitly give one type to a varible, then the compiler will infer one for us
|
||||
> Tips: If we don't explicitly assign a type to a variable, then the compiler will infer one for us.
|
||||
|
||||
```rust,editable
|
||||
|
||||
// modify `assert_eq!` to make it work
|
||||
// Modify `assert_eq!` to make it work
|
||||
fn main() {
|
||||
let x = 5;
|
||||
assert_eq!("u32".to_string(), type_of(&x));
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
// get the type of given variable, return a string representation of the type , e.g "i8", "u8", "i32", "u32"
|
||||
// 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>())
|
||||
}
|
||||
@ -55,19 +55,19 @@ fn type_of<T>(_: &T) -> String {
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blanks to make it work
|
||||
// Fill the blanks to make it work
|
||||
fn main() {
|
||||
assert_eq!(i8::MAX, __);
|
||||
assert_eq!(u8::MAX, __);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix errors and panics to make it work
|
||||
// Fix errors and panics to make it work
|
||||
fn main() {
|
||||
let v1 = 251_u8 + 8;
|
||||
let v2 = i8::checked_add(251, 8).unwrap();
|
||||
@ -78,12 +78,12 @@ fn main() {
|
||||
6. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// modify `assert!` to make it work
|
||||
// Modify `assert!` to make it work
|
||||
fn main() {
|
||||
let v = 1_024 + 0xff + 0o77 + 0b1111_1111;
|
||||
assert!(v == 1579);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -93,29 +93,29 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// replace ? with your answer
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
1. 🌟🌟 make it work in two distinct ways
|
||||
1. 🌟🌟 Make it work in two distinct ways
|
||||
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
assert!(0.1+0.2==0.3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### Range
|
||||
9. 🌟🌟 two goals: 1. modify `assert!` to make it work 2. make `println!` output: 97 - 122
|
||||
9. 🌟🌟 Two goals: 1. Modify `assert!` to make it work 2. Make `println!` output: 97 - 122
|
||||
|
||||
```rust,editable
|
||||
fn main() {
|
||||
@ -135,13 +135,13 @@ fn main() {
|
||||
10. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blanks
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -150,7 +150,7 @@ fn main() {
|
||||
11. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blanks and fix the errors
|
||||
// Fill the blanks and fix the errors
|
||||
fn main() {
|
||||
// Integer addition
|
||||
assert!(1u32 + 2 == __);
|
||||
|
@ -27,7 +27,7 @@ fn main() {
|
||||
### Exercises
|
||||
1. 🌟🌟
|
||||
```rust,editable
|
||||
// make it work with two ways
|
||||
// Make it work with two ways
|
||||
fn main() {
|
||||
let v = {
|
||||
let mut x = 1;
|
||||
@ -36,7 +36,7 @@ fn main() {
|
||||
|
||||
assert_eq!(v, 3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -48,7 +48,7 @@ fn main() {
|
||||
|
||||
assert!(v == 3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -59,7 +59,7 @@ fn main() {
|
||||
let s = sum(1 , 2);
|
||||
assert_eq!(s, 3);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn sum(x: i32, y: i32) -> i32 {
|
||||
|
@ -9,7 +9,7 @@ The hash table implementation is a Rust port of Google’s [SwissTable](https://
|
||||
### Basic Operations
|
||||
1. 🌟🌟
|
||||
|
||||
```rust,editbale
|
||||
```rust,editable
|
||||
|
||||
// FILL in the blanks and FIX the erros
|
||||
use std::collections::HashMap;
|
||||
|
@ -1,26 +1,26 @@
|
||||
# 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.
|
||||
The type of array is `[T; Length]`, as you can see, array's length is part of their type signature. So their length must be known at compile time.
|
||||
|
||||
For example, you cant initialized an array as below:
|
||||
For example, you cant initialize an array like 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.
|
||||
This will cause an error, because the compiler has no idea of the exact size of the array at compile time.
|
||||
|
||||
1. 🌟
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// fill the blank with proper array type
|
||||
// Fill the blank with proper array type
|
||||
let arr: __ = [1, 2, 3, 4, 5];
|
||||
|
||||
// modify below to make it work
|
||||
// Modify the code below to make it work
|
||||
assert!(arr.len() == 4);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -28,16 +28,16 @@ fn main() {
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// we can ignore parts of the array type or even the whole type, let the compiler infer it for us
|
||||
// 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
|
||||
// Fill the blank
|
||||
// Arrays are stack allocated, `std::mem::size_of_val` returns the bytes which an array occupies
|
||||
// A char takes 4 bytes in Rust: Unicode char
|
||||
assert!(std::mem::size_of_val(&arr) == __);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -46,13 +46,13 @@ fn main() {
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
let list: [i32; 100] = __ ;
|
||||
|
||||
assert!(list[0] == 1);
|
||||
assert!(list.len() == 100);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -60,10 +60,10 @@ fn main() {
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// fix the error
|
||||
// Fix the error
|
||||
let _arr = [1, 2, '3'];
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -73,28 +73,28 @@ fn main() {
|
||||
fn main() {
|
||||
let arr = ['a', 'b', 'c'];
|
||||
|
||||
let ele = arr[1]; // only modify this line to make the code work!
|
||||
let ele = arr[1]; // Only modify this line to make the code work!
|
||||
|
||||
assert!(ele == 'a');
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
6. 🌟 Out of bounds indexing causes `panic`.
|
||||
```rust,editable
|
||||
|
||||
// fix the error
|
||||
// Fix the error
|
||||
fn main() {
|
||||
let names = [String::from("Sunfei"), "Sunface".to_string()];
|
||||
|
||||
// `get` returns an Option<T>, it's safe to use
|
||||
// `Get` returns an Option<T>, it's safe to use
|
||||
let name0 = names.get(0).unwrap();
|
||||
|
||||
// but indexing is not safe
|
||||
// But indexing is not safe
|
||||
let _name1 = &names[2];
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fix the errors
|
||||
// Fix the errors
|
||||
enum Number {
|
||||
Zero,
|
||||
One,
|
||||
@ -25,18 +25,18 @@ enum Number2 {
|
||||
|
||||
|
||||
fn main() {
|
||||
// a enum variant can be converted to a integer by `as`
|
||||
// An enum variant can be converted to a integer by `as`
|
||||
assert_eq!(Number::One, Number1::One);
|
||||
assert_eq!(Number1::One, Number2::One);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟 each enum variant can hold its own data.
|
||||
2. 🌟 Each enum variant can hold its own data.
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank
|
||||
// Fill in the blank
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
@ -45,17 +45,17 @@ enum Message {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let msg1 = Message::Move{__}; // instantiating with x = 1, y = 2
|
||||
let msg2 = Message::Write(__); // instantiating with "hello, world!"
|
||||
let msg1 = Message::Move{__}; // Instantiating with x = 1, y = 2
|
||||
let msg2 = Message::Write(__); // Instantiating with "hello, world!"
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
3. 🌟🌟 we can get the data which a enum variant is holding by pattern match
|
||||
3. 🌟🌟 We can get the data which an enum variant is holding by pattern match.
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank and fix the error
|
||||
// Fill in the blank and fix the error
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
@ -72,7 +72,7 @@ fn main() {
|
||||
panic!("NEVER LET THIS RUN!");
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -80,7 +80,7 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank and fix the errors
|
||||
// Fill in the blank and fix the errors
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
@ -105,11 +105,11 @@ fn show_message(msg: Message) {
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟🌟 As there is no `null` in Rust, we have to use enum `Option<T>` to deal the cases when value is absent.
|
||||
5. 🌟🌟 Since there is no `null` in Rust, we have to use enum `Option<T>` to deal with the cases when the value is absent.
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank to make the `println` work.
|
||||
// also add some code to prevent the `panic` from running.
|
||||
// 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);
|
||||
@ -118,7 +118,7 @@ fn main() {
|
||||
if let __ = six {
|
||||
println!("{}", n);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
panic!("NEVER LET THIS RUN!");
|
||||
@ -133,7 +133,7 @@ fn plus_one(x: Option<i32>) -> Option<i32> {
|
||||
```
|
||||
|
||||
|
||||
6. 🌟🌟🌟🌟 implement a `linked-list` via enums.
|
||||
6. 🌟🌟🌟🌟 Implement a `linked-list` via enums.
|
||||
|
||||
```rust,editable
|
||||
|
||||
@ -166,12 +166,12 @@ impl List {
|
||||
// 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,
|
||||
// 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
|
||||
// Instead take a reference to the tail
|
||||
Cons(_, ref tail) => 1 + tail.len(),
|
||||
// Base Case: An empty list has zero length
|
||||
Nil => 0
|
||||
|
@ -4,18 +4,18 @@ Slices are similar to arrays, but their length is not known at compile time, so
|
||||
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!
|
||||
// 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!")
|
||||
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]`.
|
||||
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
|
||||
@ -25,11 +25,11 @@ fn main() {
|
||||
|
||||
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
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -38,15 +38,15 @@ fn main() {
|
||||
|
||||
fn main() {
|
||||
let arr: [i32; 5] = [1, 2, 3, 4, 5];
|
||||
// fill the blanks to make the code work
|
||||
// Fill the blanks to make the code work
|
||||
let slice: __ = __;
|
||||
assert_eq!(slice, &[2, 3, 4]);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### string slices
|
||||
### String slices
|
||||
4. 🌟
|
||||
```rust,editable
|
||||
|
||||
@ -54,12 +54,12 @@ 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
|
||||
// Fill the blank to make the code work, DON'T USE 0..2 again
|
||||
let slice2 = &s[__];
|
||||
|
||||
assert_eq!(slice1, slice2);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -68,24 +68,24 @@ fn main() {
|
||||
|
||||
fn main() {
|
||||
let s = "你好,世界";
|
||||
// modify this line to make the code work
|
||||
// Modify this line to make the code work
|
||||
let slice = &s[0..2];
|
||||
|
||||
assert!(slice == "你");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
6. 🌟🌟 `&String` can be implicitly converted into `&str`.
|
||||
```rust,editable
|
||||
|
||||
// fix errors
|
||||
// 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`
|
||||
// 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!
|
||||
|
@ -1,17 +1,17 @@
|
||||
# string
|
||||
# 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`
|
||||
### 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
|
||||
// Fix error without adding new line
|
||||
fn main() {
|
||||
let s: str = "hello, world";
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -20,9 +20,9 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fix the error with at least two solutions
|
||||
// Fix the error with at least two solutions
|
||||
fn main() {
|
||||
let s: Box<str> = "hello, world".into();
|
||||
let s: Box<str> = "hello, world".into();
|
||||
greetings(s)
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ fn greetings(s: &str) {
|
||||
3. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
fn main() {
|
||||
let mut s = __;
|
||||
s.push_str("hello, world");
|
||||
@ -45,28 +45,28 @@ fn main() {
|
||||
|
||||
assert_eq!(s, "hello, world!");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
4. 🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix all errors without adding newline
|
||||
// Fix all errors without adding newline
|
||||
fn main() {
|
||||
let s = String::from("hello");
|
||||
let s = String::from("hello");
|
||||
s.push(',');
|
||||
s.push(" world");
|
||||
s += "!".to_string();
|
||||
|
||||
println!("{}", s)
|
||||
println!("{}", s);
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟🌟 `replace` can be used to replace substring
|
||||
```rust,editable
|
||||
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
fn main() {
|
||||
let s = String::from("I like dogs");
|
||||
// Allocate new memory and store the modified string there
|
||||
@ -74,17 +74,17 @@ fn main() {
|
||||
|
||||
assert_eq!(s1, "I like cats");
|
||||
|
||||
println!("Success!")
|
||||
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
|
||||
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
|
||||
// Fix errors without removing any line
|
||||
fn main() {
|
||||
let s1 = String::from("hello,");
|
||||
let s2 = String::from("world!");
|
||||
@ -100,9 +100,9 @@ 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
|
||||
// Fix error with at least two solutions
|
||||
fn main() {
|
||||
let s = "hello, world";
|
||||
let s = "hello, world";
|
||||
greetings(s)
|
||||
}
|
||||
|
||||
@ -115,25 +115,25 @@ fn greetings(s: String) {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// use two approaches to fix the error and without adding a new line
|
||||
// Use two approaches to fix the error and without adding a new line
|
||||
fn main() {
|
||||
let s = "hello, world".to_string();
|
||||
let s = "hello, world".to_string();
|
||||
let s1: &str = s;
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### string escapes
|
||||
### 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"
|
||||
// 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.
|
||||
// ...Or Unicode code points.
|
||||
let unicode_codepoint = "\u{211D}";
|
||||
let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";
|
||||
|
||||
@ -152,9 +152,9 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
/* Fill in the blank and fix the errors */
|
||||
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
|
||||
@ -166,15 +166,14 @@ fn main() {
|
||||
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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### byte string
|
||||
### 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**:
|
||||
@ -190,8 +189,8 @@ fn main() {
|
||||
|
||||
// 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";
|
||||
// ...But no unicode escapes
|
||||
// let escaped = b"\u{211D} Is not allowed";
|
||||
println!("Some escaped bytes: {:?}", escaped);
|
||||
|
||||
|
||||
@ -208,7 +207,7 @@ fn main() {
|
||||
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
|
||||
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) {
|
||||
@ -220,29 +219,29 @@ fn main() {
|
||||
|
||||
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
|
||||
### 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
|
||||
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
|
||||
let h1 = &s1[3..5]; // Modify this line to fix the error, tips: `中` takes 3 bytes in UTF8 format
|
||||
assert_eq!(h1, "中");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### operate on UTF8 string
|
||||
### Operate on UTF8 string
|
||||
12. 🌟
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// fill the blank to print each char in "你好,世界"
|
||||
// Fill the blank to print each char in "你好,世界"
|
||||
for c in "你好,世界".__ {
|
||||
println!("{}", c)
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Struct
|
||||
|
||||
### There types of structs
|
||||
### The types of structs
|
||||
1. 🌟 We must specify concrete values for each of the fields in struct.
|
||||
```rust,editable
|
||||
|
||||
// fix the error
|
||||
// Fix the error
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
@ -17,7 +17,7 @@ fn main() {
|
||||
age,
|
||||
};
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -27,35 +27,35 @@ fn main() {
|
||||
|
||||
struct Unit;
|
||||
trait SomeTrait {
|
||||
// ...Some behavours defines here
|
||||
// ...Some behaviors defined here.
|
||||
}
|
||||
|
||||
// We don't care the the fields are in Unit, but we care its behaviors.
|
||||
// We don't care about what fields are in the Unit, but we care about 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
// fill the blank to make the code work
|
||||
// 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.
|
||||
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 to give the whole tuple a name, but don't care about the fields's names.
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fix the error and fill the blanks
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn check_color(p: Color) {
|
||||
@ -66,13 +66,13 @@ fn check_color(p: Color) {
|
||||
}
|
||||
```
|
||||
|
||||
### Operate on structs
|
||||
### Operating 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.
|
||||
4. 🌟 You can make a whole struct mutable when instantiating 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
|
||||
// Fill the blank and fix the error without adding/removing new line
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
@ -84,26 +84,26 @@ fn main() {
|
||||
age,
|
||||
};
|
||||
|
||||
// how can you believe sunface is only 18?
|
||||
// How can you believe sunface is only 18?
|
||||
p.age = 30;
|
||||
|
||||
// fill the lank
|
||||
// Fill the blank
|
||||
__ = String::from("sunfei");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟 Using *field init shorthand syntax* to reduct repetitions.
|
||||
5. 🌟 Using *field init shorthand syntax* to reduce repetitions.
|
||||
```rust,editable
|
||||
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
struct Person {
|
||||
name: String,
|
||||
age: u8,
|
||||
}
|
||||
fn main() {
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn build_person(name: String, age: u8) -> Person {
|
||||
@ -117,7 +117,7 @@ fn build_person(name: String, age: u8) -> Person {
|
||||
6. 🌟 You can create instance from other instance with *struct update syntax*
|
||||
```rust,editable
|
||||
|
||||
// fill the blank to make the code work
|
||||
// Fill the blank to make the code work
|
||||
struct User {
|
||||
active: bool,
|
||||
username: String,
|
||||
@ -134,7 +134,7 @@ fn main() {
|
||||
|
||||
let u2 = set_email(u1);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn set_email(u: User) -> User {
|
||||
@ -146,11 +146,11 @@ fn set_email(u: User) -> User {
|
||||
```
|
||||
|
||||
### 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).
|
||||
7. 🌟🌟 We can use `#[derive(Debug)]` to [make a struct printable](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
|
||||
// Fill the blanks to make the code work
|
||||
#[__]
|
||||
struct Rectangle {
|
||||
width: u32,
|
||||
@ -160,13 +160,13 @@ struct Rectangle {
|
||||
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`
|
||||
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
|
||||
dbg!(&rect1); // Print debug info to stderr
|
||||
|
||||
println!(__, rect1); // print debug info to stdout
|
||||
println!(__, rect1); // Print debug info to stdout
|
||||
}
|
||||
```
|
||||
|
||||
@ -209,7 +209,7 @@ fn main() {
|
||||
8. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix errors to make it work
|
||||
// Fix errors to make it work
|
||||
#[derive(Debug)]
|
||||
struct File {
|
||||
name: String,
|
||||
|
@ -6,29 +6,29 @@ 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
|
||||
// Fill the blanks to make the code work
|
||||
let t: (u8, __, i64, __, __) = (1u8, 2u16, 3i64, "hello", String::from(", world"));
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟 Members can be extracted from the tuple using indexing.
|
||||
```rust,editable
|
||||
|
||||
// make it works
|
||||
// Make it work
|
||||
fn main() {
|
||||
let t = ("i", "am", "sunface");
|
||||
assert_eq!(t.1, "sunface");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
3. 🌟 Long tuples cannot be printed
|
||||
```rust,editable
|
||||
|
||||
// fix the error
|
||||
// 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);
|
||||
@ -41,14 +41,14 @@ fn main() {
|
||||
fn main() {
|
||||
let tup = (1, 6.4, "hello");
|
||||
|
||||
// fill the blank to make the code work
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -57,14 +57,14 @@ fn main() {
|
||||
fn main() {
|
||||
let (x, y, z);
|
||||
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
__ = (1, 2, 3);
|
||||
|
||||
assert_eq!(x, 3);
|
||||
assert_eq!(y, 1);
|
||||
assert_eq!(z, 2);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -72,13 +72,13 @@ fn main() {
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// fill the blank, need a few computations here.
|
||||
// Fill the blank, need a few computations here.
|
||||
let (x, y) = sum_multiply(__);
|
||||
|
||||
assert_eq!(x, 5);
|
||||
assert_eq!(y, 6);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn sum_multiply(nums: (i32, i32)) -> (i32, i32) {
|
||||
|
@ -30,10 +30,15 @@ Tutorial [`https://www.philippflenker.com/hecto/`](https://www.philippflenker.co
|
||||
|
||||
[This blog series](https://os.phil-opp.com) creates a small operating system in the Rust programming language. Each post is a small tutorial and includes all needed code, so you can follow along if you like. The source code is also available in the corresponding [Github repository](https://github.com/phil-opp/blog_os).
|
||||
|
||||
|
||||
### 7. CodeCrafters.io: Build your own Git, Docker, SQLite, or Redis
|
||||
|
||||
On [CodeCrafters](https://codecrafters.io/for/rust), you can recreate your favorite developer tools from scratch. It's a hands-on, minimally-guided approach to master Rust, while appreciating the internals and documentation of popular technology that we use every day.
|
||||
|
||||
### 8. mini-redis
|
||||
[mini-redis](https://github.com/tokio-rs/mini-redis) is an incomplete Redis client and server implementation using tokio, it has decent code base and detail explanations, very suitable for learning Rust and asynchronous programming.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
# Flow control
|
||||
|
||||
### if/else
|
||||
### If/else
|
||||
1. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks
|
||||
// Fill in the blanks
|
||||
fn main() {
|
||||
let n = 5;
|
||||
|
||||
@ -18,10 +18,10 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟🌟 `if/else` expression can be used in assignments.
|
||||
2. 🌟🌟 `If/else` expression can be used in assignments.
|
||||
```rust,editable
|
||||
|
||||
// fix the errors
|
||||
// Fix the errors
|
||||
fn main() {
|
||||
let n = 5;
|
||||
|
||||
@ -40,7 +40,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### for
|
||||
### For
|
||||
3. 🌟 The `for in` construct can be used to iterate through an Iterator, e.g a range `a..b`.
|
||||
|
||||
```rust,editable
|
||||
@ -52,7 +52,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -60,19 +60,19 @@ fn main() {
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the errors without adding or removing lines
|
||||
// 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...
|
||||
// Do something with name...
|
||||
}
|
||||
|
||||
println!("{:?}", names);
|
||||
|
||||
let numbers = [1, 2, 3];
|
||||
// the elements in numbers are Copy,so there is no move here
|
||||
// The elements in numbers are Copy,so there is no move here
|
||||
for n in numbers {
|
||||
// do something with name...
|
||||
// Do something with name...
|
||||
}
|
||||
|
||||
println!("{:?}", numbers);
|
||||
@ -84,19 +84,19 @@ fn main() {
|
||||
fn main() {
|
||||
let a = [4, 3, 2, 1];
|
||||
|
||||
// iterate the indexing and value in 'a'
|
||||
// Iterate the indexing and value in 'a'
|
||||
for (i,v) in a.__ {
|
||||
println!("The {}th element is {}",i+1,v);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### while
|
||||
### 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 !
|
||||
// Fill in the blanks to make the last println! work !
|
||||
fn main() {
|
||||
// A counter variable
|
||||
let mut n = 1;
|
||||
@ -117,15 +117,15 @@ fn main() {
|
||||
__;
|
||||
}
|
||||
|
||||
println!("n reached {}, soloop is over",n);
|
||||
println!("n reached {}, so loop is over",n);
|
||||
}
|
||||
```
|
||||
|
||||
### continue and break
|
||||
7. 🌟 use `break` to break the loop.
|
||||
### Continue and break
|
||||
7. 🌟 Use `break` to break the loop.
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank
|
||||
// Fill in the blank
|
||||
fn main() {
|
||||
let mut n = 0;
|
||||
for i in 0..=100 {
|
||||
@ -137,14 +137,14 @@ fn main() {
|
||||
|
||||
assert_eq!(n, 66);
|
||||
|
||||
println!("Success!")
|
||||
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
|
||||
// Fill in the blanks
|
||||
fn main() {
|
||||
let mut n = 0;
|
||||
for i in 0..=100 {
|
||||
@ -158,17 +158,17 @@ fn main() {
|
||||
|
||||
assert_eq!(n, 66);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### loop
|
||||
### Loop
|
||||
|
||||
9. 🌟🌟 loop is usually used together with `break` or `continue`.
|
||||
9. 🌟🌟 Loop is usually used together with `break` or `continue`.
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks
|
||||
// Fill in the blanks
|
||||
fn main() {
|
||||
let mut count = 0u32;
|
||||
|
||||
@ -196,14 +196,14 @@ fn main() {
|
||||
|
||||
assert_eq!(count, 5);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
10. 🌟🌟 loop is an expression, so we can use it with `break` to return a value
|
||||
10. 🌟🌟 Loop is an expression, so we can use it with `break` to return a value
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank
|
||||
// Fill in the blank
|
||||
fn main() {
|
||||
let mut counter = 0;
|
||||
|
||||
@ -217,7 +217,7 @@ fn main() {
|
||||
|
||||
assert_eq!(result, 20);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -225,14 +225,14 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank
|
||||
// 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
|
||||
break 'inner1; // `break` is also works.
|
||||
}
|
||||
count += 2;
|
||||
}
|
||||
@ -252,7 +252,7 @@ fn main() {
|
||||
|
||||
assert!(count == __);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -173,7 +173,7 @@ fn main() {
|
||||
fn main() {
|
||||
let mut s = String::new();
|
||||
|
||||
let update_string = |str| s.push_str(str);
|
||||
let update_string = |str| s.push_str(str);
|
||||
|
||||
exec(update_string);
|
||||
|
||||
@ -260,7 +260,7 @@ move closures may still implement `Fn` or `FnMut`, even though they capture vari
|
||||
fn main() {
|
||||
let s = String::new();
|
||||
|
||||
let update_string = move || println!("{}",s);
|
||||
let update_string = move || println!("{}",s);
|
||||
|
||||
exec(update_string);
|
||||
}
|
||||
@ -275,7 +275,7 @@ The following code also has no error:
|
||||
fn main() {
|
||||
let s = String::new();
|
||||
|
||||
let update_string = move || println!("{}",s);
|
||||
let update_string = move || println!("{}",s);
|
||||
|
||||
exec(update_string);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ pub trait CacheableItem: Clone + Default + fmt::Debug + Decodable + Encodable {
|
||||
}
|
||||
```
|
||||
|
||||
Using of `Address` is much more clearable and convenient than `AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash`.
|
||||
Using of `Address` is much more clearer and convenient than `AsRef<[u8]> + Clone + fmt::Debug + Eq + Hash`.
|
||||
|
||||
1. 🌟🌟🌟
|
||||
```rust,editable
|
||||
@ -89,7 +89,7 @@ fn main() {
|
||||
assert_eq!(Point { x: 2, y: 3 } - Point { x: 1, y: 0 },
|
||||
Point { x: 1, y: 3 });
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -110,7 +110,7 @@ trait AgeWidget {
|
||||
fn get(&self) -> u8;
|
||||
}
|
||||
|
||||
// A form with both a UsernameWidget and an AgeWidget
|
||||
// A form with both a UsernameWidget and an AgeWidget.
|
||||
struct Form {
|
||||
username: String,
|
||||
age: u8,
|
||||
@ -141,10 +141,10 @@ fn main() {
|
||||
|
||||
let username = UsernameWidget::get(&form);
|
||||
assert_eq!("rustacean".to_owned(), username);
|
||||
let age = AgeWidget::get(&form); // you can also use `<Form as AgeWidget>::get`
|
||||
let age = AgeWidget::get(&form); // You can also use `<Form as AgeWidget>::get`
|
||||
assert_eq!(28, age);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -187,7 +187,7 @@ fn main() {
|
||||
|
||||
assert_eq!(__, "*waving arms furiously*");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -253,7 +253,7 @@ fn main() {
|
||||
## Orphan Rules
|
||||
We can’t implement external traits on external types. For example, we can’t implement the `Display` trait on `Vec<T>` within our own crate, because `Display` and `Vec<T>` are defined in the standard library and aren’t 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 people’s code can’t break your code and vice versa.
|
||||
This restriction is often called the orphan rule, so named because the parent type is not present. This rule ensures that other people’s code can’t break your code and vice versa.
|
||||
|
||||
It’s possible to get around this restriction using the newtype pattern, which involves creating a new type in a tuple struct.
|
||||
|
||||
|
@ -25,15 +25,15 @@ impl<T: Debug, const N: usize> Debug for ArrayPair<T, N> {
|
||||
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>(); // Okay: `M` is a const parameter
|
||||
foo::<2021>(); // Okay: `2021` is a literal
|
||||
foo::<{20 * 100 + 20 * 10 + 1}>(); // Okay: 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`
|
||||
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`
|
||||
let _: [u8; M]; // Okay: `M` is a const parameter
|
||||
let _: [u8; std::mem::size_of::<T>()]; // Error: const expression contains the generic parameter `T`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@ -89,14 +89,14 @@ fn main() {
|
||||
}
|
||||
];
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks to make it work
|
||||
// Fill in the blanks to make it work.
|
||||
fn print_array<__>(__) {
|
||||
println!("{:?}", arr);
|
||||
}
|
||||
@ -109,7 +109,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
3. 🌟🌟🌟 Sometimes we want to limit the size of a variable, e.g when using in embedding environments, then `const expressions` will fit your needs.
|
||||
|
||||
```rust,editable
|
||||
#![allow(incomplete_features)]
|
||||
@ -122,15 +122,15 @@ where
|
||||
//...
|
||||
}
|
||||
|
||||
// fix the errors in main
|
||||
// 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 ?
|
||||
check_size(["hello你好"; __]); // Size of &str ?
|
||||
check_size([(); __].map(|_| "hello你好".to_string())); // Size of String?
|
||||
check_size(['中'; __]); // Size of char ?
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
1. 🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks to make it work
|
||||
// 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`.
|
||||
@ -29,14 +29,14 @@ fn main() {
|
||||
// Implicitly specified type parameter `char` to `generic()`.
|
||||
generic(__);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟🌟 A function call with explicitly specified type parameters looks like: `fun::<A, B, ...>()`.
|
||||
```rust,editable
|
||||
|
||||
// implement the generic function below
|
||||
// Implement the generic function below.
|
||||
fn sum
|
||||
|
||||
fn main() {
|
||||
@ -44,7 +44,7 @@ fn main() {
|
||||
assert_eq!(50, sum(20, 30));
|
||||
assert_eq!(2.46, sum(1.23, 1.23));
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -54,38 +54,38 @@ fn main() {
|
||||
3. 🌟
|
||||
```rust,editable
|
||||
|
||||
// implement struct Point to make it work
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// modify this struct to make the code work
|
||||
// Modify this struct to make the code work
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// DON'T modify here
|
||||
// DON'T modify this code.
|
||||
let p = Point{x: 5, y : "hello".to_string()};
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// add generic for Val to make the code work, DON'T modify the code in `main`
|
||||
// Add generic for Val to make the code work, DON'T modify the code in `main`.
|
||||
struct Val {
|
||||
val: f64,
|
||||
}
|
||||
@ -114,7 +114,7 @@ struct Point<T, U> {
|
||||
}
|
||||
|
||||
impl<T, U> Point<T, U> {
|
||||
// implement mixup to make it work, DON'T modify other code
|
||||
// Implement mixup to make it work, DON'T modify other code.
|
||||
fn mixup
|
||||
}
|
||||
|
||||
@ -127,14 +127,14 @@ fn main() {
|
||||
assert_eq!(p3.x, 5);
|
||||
assert_eq!(p3.y, '中');
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
7. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the errors to make the code work
|
||||
// Fix the errors to make the code work.
|
||||
struct Point<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
@ -148,7 +148,7 @@ impl Point<f32> {
|
||||
|
||||
fn main() {
|
||||
let p = Point{x: 5, y: 10};
|
||||
println!("{}",p.distance_from_origin())
|
||||
println!("{}",p.distance_from_origin());
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -4,7 +4,7 @@ In [traits chapter](https://practice.rs/generics-traits/traits.html#returning-ty
|
||||
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`.
|
||||
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 memory, 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
|
||||
@ -39,26 +39,26 @@ impl Bird for Swan {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// FILL in the blank
|
||||
// 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
|
||||
// This bird has forgotten how to swim, so below line will cause an error.
|
||||
// bird.swim();
|
||||
// but it can quak
|
||||
// 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
|
||||
// This bird has forgotten how to fly, so below line will cause an error.
|
||||
// bird.fly();
|
||||
// but it can quak too
|
||||
// But it can quak too.
|
||||
assert_eq!(bird.quack(), "swan swan");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
// IMPLEMENT this function
|
||||
// IMPLEMENT this function.
|
||||
fn hatch_a_bird...
|
||||
|
||||
```
|
||||
@ -95,13 +95,13 @@ impl Bird for Swan {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// FILL in the blank to make the code work
|
||||
// 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
|
||||
// When duck and swan turn into Birds, they all forgot how to fly, only remember how to quack.
|
||||
// So, the code below will cause an error.
|
||||
// bird.fly();
|
||||
}
|
||||
}
|
||||
@ -113,7 +113,7 @@ fn main() {
|
||||
3. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// FILL in the blanks
|
||||
// FILL in the blanks.
|
||||
trait Draw {
|
||||
fn draw(&self) -> String;
|
||||
}
|
||||
@ -134,13 +134,13 @@ fn main() {
|
||||
let x = 1.1f64;
|
||||
let y = 8u8;
|
||||
|
||||
// draw x
|
||||
// Draw x.
|
||||
draw_with_box(__);
|
||||
|
||||
// draw y
|
||||
// Draw y.
|
||||
draw_with_ref(&y);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn draw_with_box(x: Box<dyn Draw>) {
|
||||
@ -153,11 +153,11 @@ fn draw_with_ref(x: __) {
|
||||
```
|
||||
|
||||
## 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 you’re calling at compile time.
|
||||
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 you’re calling at compile time.
|
||||
|
||||
When we use trait objects, Rust must use dynamic dispatch. The compiler doesn’t know all the types that might be used with the code that is using trait objects, so it doesn’t 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 doesn’t occur with static dispatch. Dynamic dispatch also prevents the compiler from choosing to inline a method’s code, which in turn prevents some optimizations.
|
||||
|
||||
However, we did get extra flexibility when using dynamic dispatch.
|
||||
However, we do get extra flexibility when using dynamic dispatch.
|
||||
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
@ -174,10 +174,10 @@ impl Foo for String {
|
||||
fn method(&self) -> String { format!("string: {}", *self) }
|
||||
}
|
||||
|
||||
// IMPLEMENT below with generics
|
||||
// IMPLEMENT below with generics.
|
||||
fn static_dispatch...
|
||||
|
||||
// implement below with trait objects
|
||||
// Implement below with trait objects.
|
||||
fn dynamic_dispatch...
|
||||
|
||||
fn main() {
|
||||
@ -187,7 +187,7 @@ fn main() {
|
||||
static_dispatch(x);
|
||||
dynamic_dispatch(&y);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -200,8 +200,8 @@ You can only make object-safe traits into trait objects. A trait is object safe
|
||||
5. 🌟🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// Use at least two approaches to make it work
|
||||
// DON'T add/remove any code line
|
||||
// Use at least two approaches to make it work.
|
||||
// DON'T add/remove any code line.
|
||||
trait MyTrait {
|
||||
fn f(&self) -> Self;
|
||||
}
|
||||
@ -222,7 +222,7 @@ fn main() {
|
||||
my_function(Box::new(13_u32));
|
||||
my_function(Box::new(String::from("abc")));
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -81,8 +81,8 @@ fn main() {
|
||||
1. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the two impl blocks to make the code work
|
||||
// DON'T modify the code in `main`
|
||||
// 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")
|
||||
@ -107,7 +107,7 @@ fn main() {
|
||||
assert_eq!(t.say_hi(), "Hi, I'm your new teacher");
|
||||
assert_eq!(t.say_something(), "I'm not a bad teacher");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -135,7 +135,7 @@ impl Inches {
|
||||
}
|
||||
|
||||
// ADD some attributes to make the code work!
|
||||
// DON'T modify other codes!
|
||||
// DON'T modify other code!
|
||||
struct Seconds(i32);
|
||||
|
||||
fn main() {
|
||||
@ -171,23 +171,23 @@ In Rust, many of the operators can be overloaded via traits. That is, some opera
|
||||
|
||||
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/
|
||||
// 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!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
4. 🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the errors, DON'T modify the code in `main`
|
||||
// Fix the errors, DON'T modify the code in `main`.
|
||||
use std::ops;
|
||||
|
||||
struct Foo;
|
||||
@ -217,12 +217,12 @@ impl ops::Sub<Foo> for Bar {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// DON'T modify the below code
|
||||
// you need to derive some trait for FooBar to make it comparable
|
||||
// DON'T modify the code below.
|
||||
// You need to derive some trait for FooBar to make it comparable.
|
||||
assert_eq!(Foo + Bar, FooBar);
|
||||
assert_eq!(Foo - Bar, BarFoo);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -232,8 +232,8 @@ Instead of a concrete type for the item parameter, we specify the impl keyword a
|
||||
5. 🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// implement `fn summary` to make the code work
|
||||
// fix the errors without removing any code line
|
||||
// Implement `fn summary` to make the code work.
|
||||
// Fix the errors without removing any code line
|
||||
trait Summary {
|
||||
fn summarize(&self) -> String;
|
||||
}
|
||||
@ -281,14 +281,14 @@ fn main() {
|
||||
println!("{:?}", weibo);
|
||||
}
|
||||
|
||||
// implement `fn summary` below
|
||||
// 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 you’re returning a single type, using Trait Objects instead when you really need to return serveral types.
|
||||
However, you can only use impl Trait if you’re returning a single type, use Trait Objects instead when you really need to return several types.
|
||||
|
||||
6. 🌟🌟
|
||||
```rust,editable
|
||||
@ -313,7 +313,7 @@ impl Animal for Cow {
|
||||
}
|
||||
|
||||
// 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
|
||||
// FIX the errors 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 {}
|
||||
@ -340,7 +340,7 @@ fn main() {
|
||||
assert_eq!(sum(1, 2), 3);
|
||||
}
|
||||
|
||||
// implement `fn sum` with trait bound in two ways
|
||||
// Implement `fn sum` with trait bound in two ways.
|
||||
fn sum<T>(x: T, y: T) -> T {
|
||||
x + y
|
||||
}
|
||||
@ -348,7 +348,7 @@ fn sum<T>(x: T, y: T) -> T {
|
||||
8. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// FIX the errors
|
||||
// FIX the errors.
|
||||
struct Pair<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
@ -388,10 +388,10 @@ fn main() {
|
||||
9. 🌟🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks to make it work
|
||||
// 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`
|
||||
// `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>,
|
||||
@ -424,7 +424,7 @@ fn example1() {
|
||||
|
||||
|
||||
fn example2() {
|
||||
// We can also use `where` to constrain `T`
|
||||
// We can also use `where` to construct `T`
|
||||
struct Cacher<T>
|
||||
where T: Fn(u32) -> u32,
|
||||
{
|
||||
@ -465,7 +465,7 @@ fn main() {
|
||||
example1();
|
||||
example2();
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Associated function & Method
|
||||
# Associated functions & Methods
|
||||
|
||||
## Examples
|
||||
```rust,editable
|
||||
@ -7,7 +7,7 @@ struct Point {
|
||||
y: f64,
|
||||
}
|
||||
|
||||
// Implementation block, all `Point` associated functions & methods go in here
|
||||
// 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.
|
||||
@ -30,11 +30,11 @@ struct Rectangle {
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
// This is a method
|
||||
// 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
|
||||
// `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;
|
||||
|
||||
@ -61,7 +61,7 @@ impl Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// `Pair` owns resources: two heap allocated integers
|
||||
// `Pair` owns resources: two heap allocated integers.
|
||||
struct Pair(Box<i32>, Box<i32>);
|
||||
|
||||
impl Pair {
|
||||
@ -73,7 +73,7 @@ impl Pair {
|
||||
|
||||
println!("Destroying Pair({}, {})", first, second);
|
||||
|
||||
// `first` and `second` go out of scope and get freed
|
||||
// `first` and `second` go out of scope and get freed.
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ fn main() {
|
||||
p2: Point::new(3.0, 4.0),
|
||||
};
|
||||
|
||||
// Methods are called using the dot operator
|
||||
// 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());
|
||||
@ -96,7 +96,7 @@ fn main() {
|
||||
};
|
||||
|
||||
// Error! `rectangle` is immutable, but this method requires a mutable
|
||||
// object
|
||||
// object.
|
||||
//rectangle.translate(1.0, 0.0);
|
||||
// TODO ^ Try uncommenting this line
|
||||
|
||||
@ -116,7 +116,7 @@ fn main() {
|
||||
## 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.
|
||||
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,
|
||||
@ -124,7 +124,7 @@ struct Rectangle {
|
||||
}
|
||||
|
||||
impl Rectangle {
|
||||
// complete the area method which return the area of a Rectangle
|
||||
// Complete the area method which return the area of a Rectangle.
|
||||
fn area
|
||||
}
|
||||
|
||||
@ -133,11 +133,11 @@ fn main() {
|
||||
|
||||
assert_eq!(rect1.area(), 1500);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟🌟 `self` will take the ownership of current struct instance, however, `&self` will only borrow a reference from the instance
|
||||
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!
|
||||
@ -155,9 +155,9 @@ fn main() {
|
||||
let light = TrafficLight{
|
||||
color: "red".to_owned(),
|
||||
};
|
||||
// Don't take the ownership of `light` here
|
||||
// Don't take the ownership of `light` here.
|
||||
light.show_state();
|
||||
// ..otherwise, there will be an error below
|
||||
// ... Otherwise, there will be an error below
|
||||
println!("{:?}", light);
|
||||
}
|
||||
```
|
||||
@ -168,23 +168,23 @@ struct TrafficLight {
|
||||
}
|
||||
|
||||
impl TrafficLight {
|
||||
// using `Self` to fill in the blank
|
||||
// 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() {
|
||||
// Fill in the blank, DON'T use any variants of `Self`.
|
||||
pub fn change_state(__) {
|
||||
self.color = "green".to_string()
|
||||
}
|
||||
}
|
||||
fn main() {
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Associated function
|
||||
### Associated functions
|
||||
|
||||
4. 🌟🌟 All functions defined within an `impl` block are called associated functions because they’re associated with the type named after the `impl`. We can define associated functions that don’t have `self` as their first parameter (and thus are not methods) because they don’t need an instance of the type to work with.
|
||||
|
||||
@ -195,9 +195,9 @@ struct TrafficLight {
|
||||
}
|
||||
|
||||
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
|
||||
// 1. Implement an 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 {
|
||||
@ -209,7 +209,7 @@ fn main() {
|
||||
let light = TrafficLight::new();
|
||||
assert_eq!(light.get_state(), "red");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -222,7 +222,7 @@ struct Rectangle {
|
||||
height: u32,
|
||||
}
|
||||
|
||||
// using multiple `impl` blocks to rewrite the code below
|
||||
// Using multiple `impl` blocks to rewrite the code below.
|
||||
impl Rectangle {
|
||||
fn area(&self) -> u32 {
|
||||
self.width * self.height
|
||||
@ -235,7 +235,7 @@ impl Rectangle {
|
||||
|
||||
|
||||
fn main() {
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -251,7 +251,7 @@ enum TrafficLightColor {
|
||||
Green,
|
||||
}
|
||||
|
||||
// implement TrafficLightColor with a method
|
||||
// Implement TrafficLightColor with a method.
|
||||
impl TrafficLightColor {
|
||||
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
// fill the blank
|
||||
// Fill the blank
|
||||
let p = __;
|
||||
|
||||
println!("the memory address of x is {:p}", p); // one possible output: 0x16fa3ac84
|
||||
println!("the memory address of x is {:p}", p); // One possible output: 0x16fa3ac84
|
||||
}
|
||||
```
|
||||
|
||||
@ -20,23 +20,23 @@ fn main() {
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
// modify this line only
|
||||
// Modify this line only
|
||||
assert_eq!(5, y);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
3. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fix error
|
||||
// Fix error
|
||||
fn main() {
|
||||
let mut s = String::from("hello, ");
|
||||
|
||||
borrow_object(s);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn borrow_object(s: &String) {}
|
||||
@ -45,13 +45,13 @@ fn borrow_object(s: &String) {}
|
||||
4. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fix error
|
||||
// Fix error
|
||||
fn main() {
|
||||
let mut s = String::from("hello, ");
|
||||
|
||||
push_str(s);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn push_str(s: &mut String) {
|
||||
@ -65,16 +65,16 @@ fn push_str(s: &mut String) {
|
||||
fn main() {
|
||||
let mut s = String::from("hello, ");
|
||||
|
||||
// fill the blank to make it work
|
||||
// Fill the blank to make it work
|
||||
let p = __;
|
||||
|
||||
p.push_str("world");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
#### ref
|
||||
#### Ref
|
||||
`ref` can be used to take references to a value, similar to `&`.
|
||||
|
||||
6. 🌟🌟🌟
|
||||
@ -84,18 +84,18 @@ fn main() {
|
||||
let c = '中';
|
||||
|
||||
let r1 = &c;
|
||||
// fill the blank,dont change other code
|
||||
// Fill the blank,dont change other code
|
||||
let __ r2 = c;
|
||||
|
||||
assert_eq!(*r1, *r2);
|
||||
|
||||
// check the equality of the two address strings
|
||||
// Check the equality of the two address strings
|
||||
assert_eq!(get_addr(r1),get_addr(r2));
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
// get memory address string
|
||||
// Get memory address string
|
||||
fn get_addr(r: &char) -> String {
|
||||
format!("{:p}", r)
|
||||
}
|
||||
@ -105,8 +105,8 @@ fn get_addr(r: &char) -> String {
|
||||
7. 🌟
|
||||
```rust,editable
|
||||
|
||||
// remove something to make it work
|
||||
// don't remove a whole line !
|
||||
// Remove something to make it work
|
||||
// Don't remove a whole line !
|
||||
fn main() {
|
||||
let mut s = String::from("hello");
|
||||
|
||||
@ -115,21 +115,21 @@ fn main() {
|
||||
|
||||
println!("{}, {}", r1, r2);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
#### Mutablity
|
||||
8. 🌟 Error: Borrow a immutable object as mutable
|
||||
#### Mutability
|
||||
8. 🌟 Error: Borrow an immutable object as mutable
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
//fix error by modifying this line
|
||||
// Fix error by modifying this line
|
||||
let s = String::from("hello, ");
|
||||
|
||||
borrow_object(&mut s);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn borrow_object(s: &mut String) {}
|
||||
@ -138,7 +138,7 @@ fn borrow_object(s: &mut String) {}
|
||||
9. 🌟🌟 Ok: Borrow a mutable object as immutable
|
||||
```rust,editable
|
||||
|
||||
// this code has no errors!
|
||||
// This code has no errors!
|
||||
fn main() {
|
||||
let mut s = String::from("hello, ");
|
||||
|
||||
@ -146,7 +146,7 @@ fn main() {
|
||||
|
||||
s.push_str("world");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn borrow_object(s: &String) {}
|
||||
@ -156,7 +156,7 @@ fn borrow_object(s: &String) {}
|
||||
10. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// comment one line to make it work
|
||||
// Comment one line to make it work
|
||||
fn main() {
|
||||
let mut s = String::from("hello, ");
|
||||
|
||||
@ -178,8 +178,8 @@ fn main() {
|
||||
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
|
||||
// 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
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
```rust,editable
|
||||
|
||||
fn main() {
|
||||
// use as many approaches as you can to make it work
|
||||
// Use as many approaches as you can to make it work
|
||||
let x = String::from("hello, world");
|
||||
let y = x;
|
||||
println!("{},{}",x,y);
|
||||
@ -39,7 +39,7 @@ fn main() {
|
||||
// Only modify the code below!
|
||||
fn give_ownership() -> String {
|
||||
let s = String::from("hello, world");
|
||||
// convert String to Vec
|
||||
// Convert String to Vec
|
||||
let _s = s.into_bytes();
|
||||
s
|
||||
}
|
||||
@ -47,7 +47,7 @@ fn give_ownership() -> String {
|
||||
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
// fix the error without removing code line
|
||||
// Fix the error without removing code line
|
||||
fn main() {
|
||||
let s = String::from("hello, world");
|
||||
|
||||
@ -63,7 +63,7 @@ fn print_str(s: String) {
|
||||
|
||||
5. 🌟🌟
|
||||
```rust, editable
|
||||
// don't use clone ,use copy instead
|
||||
// Don't use clone ,use copy instead
|
||||
fn main() {
|
||||
let x = (1, 2, (), "hello".to_string());
|
||||
let y = x.clone();
|
||||
@ -80,12 +80,12 @@ Mutability can be changed when ownership is transferred.
|
||||
fn main() {
|
||||
let s = String::from("hello, ");
|
||||
|
||||
// modify this line only !
|
||||
// Modify this line only !
|
||||
let s1 = s;
|
||||
|
||||
s1.push_str("world");
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -95,13 +95,13 @@ fn main() {
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
let ... // implement this line, dont change other lines!
|
||||
let ... // Implement this line, dont change other lines!
|
||||
|
||||
*y = 4;
|
||||
|
||||
assert_eq!(*x, 5);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -148,7 +148,7 @@ fn main() {
|
||||
|
||||
let _s = t.0;
|
||||
|
||||
// modify this line only, don't use `_s`
|
||||
// Modify this line only, don't use `_s`
|
||||
println!("{:?}", t);
|
||||
}
|
||||
```
|
||||
@ -159,7 +159,7 @@ fn main() {
|
||||
fn main() {
|
||||
let t = (String::from("hello"), String::from("world"));
|
||||
|
||||
// fill the blanks
|
||||
// Fill the blanks
|
||||
let (__, __) = __;
|
||||
|
||||
println!("{:?}, {:?}, {:?}", s1, s2, t); // -> "hello", "world", ("hello", "world")
|
||||
|
@ -1,10 +1,10 @@
|
||||
# match, if let
|
||||
# Match, if let
|
||||
|
||||
### match
|
||||
### Match
|
||||
1. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill the blanks
|
||||
// Fill the blanks
|
||||
enum Direction {
|
||||
East,
|
||||
West,
|
||||
@ -16,7 +16,7 @@ fn main() {
|
||||
let dire = Direction::South;
|
||||
match dire {
|
||||
Direction::East => println!("East"),
|
||||
__ => { // matching South or North here
|
||||
__ => { // Matching South or North here
|
||||
println!("South or North");
|
||||
},
|
||||
_ => println!(__),
|
||||
@ -24,13 +24,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟🌟 match is an expression, so we can use it in assignments
|
||||
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:
|
||||
// Fill the blank with a match expression:
|
||||
//
|
||||
// boolean = true => binary = 1
|
||||
// boolean = false => binary = 0
|
||||
@ -38,14 +38,14 @@ fn main() {
|
||||
|
||||
assert_eq!(binary, 1);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
3. 🌟🌟 using match to get the data an enum variant holds
|
||||
3. 🌟🌟 Using match to get the data an enum variant holds.
|
||||
```rust,editable
|
||||
|
||||
// fill in the blanks
|
||||
// Fill in the blanks
|
||||
enum Message {
|
||||
Quit,
|
||||
Move { x: i32, y: i32 },
|
||||
@ -64,7 +64,7 @@ fn main() {
|
||||
show_message(msg)
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
|
||||
fn show_message(msg: Message) {
|
||||
@ -83,7 +83,7 @@ fn show_message(msg: Message) {
|
||||
```
|
||||
|
||||
### matches!
|
||||
[`matches!`](https://doc.rust-lang.org/stable/core/macro.matches.html) looks like `match`, but can do something different
|
||||
[`matches!`](https://doc.rust-lang.org/stable/core/macro.matches.html) looks like `match`, but can do something different.
|
||||
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
@ -91,12 +91,12 @@ fn show_message(msg: Message) {
|
||||
fn main() {
|
||||
let alphabets = ['a', 'E', 'Z', '0', 'x', '9' , 'Y'];
|
||||
|
||||
// fill the blank with `matches!` to make the code work
|
||||
// Fill the blank with `matches!` to make the code work
|
||||
for ab in alphabets {
|
||||
assert!(__)
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -113,19 +113,19 @@ fn main() {
|
||||
|
||||
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
|
||||
if e == MyEnum::Foo { // Fix the error by changing only this line
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(count, 2);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### if let
|
||||
For some cases, when matching enums, `match` is too heavy, we can use `if let` instead.
|
||||
### If let
|
||||
For some cases, when matching enums, `match` is too heavy. We can use `if let` instead.
|
||||
|
||||
6. 🌟
|
||||
```rust,editable
|
||||
@ -133,12 +133,12 @@ For some cases, when matching enums, `match` is too heavy, we can use `if let` i
|
||||
fn main() {
|
||||
let o = Some(7);
|
||||
|
||||
// remove the whole `match` block, using `if let` instead
|
||||
// Remove the whole `match` block, using `if let` instead
|
||||
match o {
|
||||
Some(i) => {
|
||||
println!("This is a really long string and `{:?}`", i);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
@ -148,7 +148,7 @@ fn main() {
|
||||
7. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fill in the blank
|
||||
// Fill in the blank
|
||||
enum Foo {
|
||||
Bar(u8)
|
||||
}
|
||||
@ -159,7 +159,7 @@ fn main() {
|
||||
__ {
|
||||
println!("foobar holds the value: {}", i);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -176,7 +176,7 @@ enum Foo {
|
||||
fn main() {
|
||||
let a = Foo::Qux(10);
|
||||
|
||||
// remove the codes below, using `match` instead
|
||||
// Remove the codes below, using `match` instead
|
||||
if let Foo::Bar = a {
|
||||
println!("match foo::bar")
|
||||
} else if let Foo::Baz = a {
|
||||
@ -191,15 +191,15 @@ fn main() {
|
||||
9. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the errors in-place
|
||||
// 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`
|
||||
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
|
||||
} // The new variable `age` goes out of scope here
|
||||
|
||||
match age {
|
||||
// match can also introduce a new shadowed variable
|
||||
// Match can also introduce a new shadowed variable
|
||||
Some(age) => println!("age is a new variable, it's value is {}",age),
|
||||
_ => ()
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
# Patterns
|
||||
|
||||
1. 🌟🌟 use `|` to match several values, use `..=` to match a inclusive range
|
||||
1. 🌟🌟 Use `|` to match several values, use `..=` to match an inclusive range.
|
||||
```rust,editable
|
||||
|
||||
fn main() {}
|
||||
fn match_number(n: i32) {
|
||||
match n {
|
||||
// match a single value
|
||||
// Match a single value
|
||||
1 => println!("One!"),
|
||||
// fill in the blank with `|`, DON'T use `..` ofr `..=`
|
||||
// Fill in the blank with `|`, DON'T use `..` or `..=`
|
||||
__ => println!("match 2 -> 5"),
|
||||
// match an inclusive range
|
||||
// Match an inclusive range
|
||||
6..=10 => {
|
||||
println!("match 6 -> 10")
|
||||
},
|
||||
@ -21,7 +21,7 @@ fn match_number(n: i32) {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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 {
|
||||
@ -30,12 +30,12 @@ struct Point {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// fill in the blank to let p match the second arm
|
||||
// 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
|
||||
// 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),
|
||||
}
|
||||
@ -46,7 +46,7 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fix the errors
|
||||
// Fix the errors
|
||||
enum Message {
|
||||
Hello { id: i32 },
|
||||
}
|
||||
@ -69,7 +69,7 @@ fn main() {
|
||||
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
|
||||
// Fill in the blank to make the code work, `split` MUST be used
|
||||
fn main() {
|
||||
let num = Some(4);
|
||||
let split = 5;
|
||||
@ -79,14 +79,14 @@ fn main() {
|
||||
None => (),
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
5. 🌟🌟 Ignoring remaining parts of the value with `..`
|
||||
```rust,editable
|
||||
|
||||
// fill the blank to make the code work
|
||||
// Fill the blank to make the code work
|
||||
fn main() {
|
||||
let numbers = (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048);
|
||||
|
||||
@ -97,11 +97,11 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
println!("Success!")
|
||||
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
|
||||
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
|
||||
|
@ -1,29 +1,29 @@
|
||||
# Variables
|
||||
|
||||
### Binding and mutablity
|
||||
### Binding and mutability
|
||||
1. 🌟 A variable can be used only if it has been initialized.
|
||||
```rust,editable
|
||||
|
||||
// fix the error below with least modifying
|
||||
// Fix the error below with least amount of modification to the code
|
||||
fn main() {
|
||||
let x: i32; // uninitialized but using, ERROR !
|
||||
let y: i32; // uninitialized but also unusing, only warning
|
||||
let x: i32; // Uninitialized but used, ERROR !
|
||||
let y: i32; // Uninitialized but also unused, only a Warning !
|
||||
|
||||
assert_eq!(x, 5);
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
2. 🌟 Use `mut` to mark a variable as mutable.
|
||||
```rust,editable
|
||||
|
||||
// fill the blanks in code to make it compile
|
||||
// Fill the blanks in the code to make it compile
|
||||
fn main() {
|
||||
let __ = 1;
|
||||
let __ = 1;
|
||||
__ += 2;
|
||||
|
||||
assert_eq!(x, 3);
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
@ -33,7 +33,7 @@ A scope is the range within the program for which the item is valid.
|
||||
3. 🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the error below with least modifying
|
||||
// Fix the error below with least amount of modification
|
||||
fn main() {
|
||||
let x: i32 = 10;
|
||||
{
|
||||
@ -47,7 +47,7 @@ fn main() {
|
||||
4. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// fix the error with using of define_x
|
||||
// Fix the error with the use of define_x
|
||||
fn main() {
|
||||
println!("{}, world", x);
|
||||
}
|
||||
@ -63,7 +63,7 @@ You can declare a new variable with the same name as a previous variable, here w
|
||||
5. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// only modify `assert_eq!` to make the `println!` work(print `42` in terminal)
|
||||
// Only modify `assert_eq!` to make the `println!` work(print `42` in terminal)
|
||||
fn main() {
|
||||
let x: i32 = 5;
|
||||
{
|
||||
@ -73,7 +73,7 @@ fn main() {
|
||||
|
||||
assert_eq!(x, 12);
|
||||
|
||||
let x = 42;
|
||||
let x = 42;
|
||||
println!("{}", x); // Prints "42".
|
||||
}
|
||||
```
|
||||
@ -81,28 +81,28 @@ fn main() {
|
||||
6. 🌟🌟
|
||||
```rust,editable
|
||||
|
||||
// remove a line in code to make it compile
|
||||
// Remove a line in the code to make it compile
|
||||
fn main() {
|
||||
let mut x: i32 = 1;
|
||||
x = 7;
|
||||
// shadowing and re-binding
|
||||
// Shadowing and re-binding
|
||||
let x = x;
|
||||
x += 3;
|
||||
|
||||
|
||||
let y = 4;
|
||||
// shadowing
|
||||
// Shadowing
|
||||
let y = "I can also be bound to text!";
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
### Unused varibles
|
||||
1. fix the warning below with :
|
||||
### Unused variables
|
||||
1. Fix the warning below with :
|
||||
|
||||
- 🌟 only one solution
|
||||
- 🌟🌟 two distinct solutions
|
||||
- 🌟 Only one solution
|
||||
- 🌟🌟 Two distinct solutions
|
||||
|
||||
> Note: none of the solutions is to remove the line `let x = 1`
|
||||
|
||||
@ -112,7 +112,7 @@ fn main() {
|
||||
let x = 1;
|
||||
}
|
||||
|
||||
// warning: unused variable: `x`
|
||||
// Warning: unused variable: `x`
|
||||
```
|
||||
|
||||
### Destructuring
|
||||
@ -122,7 +122,7 @@ fn main() {
|
||||
|
||||
```rust,editable
|
||||
|
||||
// fix the error below with least modifying
|
||||
// Fix the error below with least amount of modification
|
||||
fn main() {
|
||||
let (x, y) = (1, 2);
|
||||
x += 2;
|
||||
@ -130,12 +130,12 @@ fn main() {
|
||||
assert_eq!(x, 3);
|
||||
assert_eq!(y, 2);
|
||||
|
||||
println!("Success!")
|
||||
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.
|
||||
Introduced in Rust 1.59: You can now use tuple, slice, and struct patterns as the left-hand side of an assignment.
|
||||
|
||||
9. 🌟🌟
|
||||
|
||||
@ -147,10 +147,10 @@ fn main() {
|
||||
let (x, y);
|
||||
(x,..) = (3, 4);
|
||||
[.., y] = [1, 2];
|
||||
// fill the blank to make the code work
|
||||
// Fill the blank to make the code work
|
||||
assert_eq!([x,y], __);
|
||||
|
||||
println!("Success!")
|
||||
println!("Success!");
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<div align="center">
|
||||
<img height="150" src="https://github.com/sunface/rust-by-practice/blob/master/en/assets/logo.png?raw=true">
|
||||
<img src="https://github.com/sunface/rust-by-practice/blob/master/en/assets/header.png?raw=true">
|
||||
</div>
|
||||
|
||||
<p align="center">Practice Rust with challenging examples, exercises and projects</p>
|
||||
|
Reference in New Issue
Block a user