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

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