时间轴

2025-10-27

init


环境搭建

1
2
3
4
5
6
7
8
9
10
11
12
# Installation
cargo install rustlings
# Initialization
rustlings init
# Moving into new directory
cd rustlings
# 进入rustlings命令行模式
rustlings
# 检查所有题目
rustlings check-all
# 运行某一个题目
rustlings run primitive_types2

variable

常量定义要加上类型!
variable6

1
2
3
4
5
6
7
// TODO: Change the line below to fix the compiler error.
const NUMBER: i32 = 3;

fn main() {
println!("Number: {NUMBER}");
}

move_semantics

vec 声明需要为 mut , 参数也得是 mut

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fn fill_vec(mut vec: Vec<i32>) -> Vec<i32> {
vec.push(88);

vec
}

fn main() {
// You can optionally experiment here.
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn move_semantics3() {
let mut vec0 = vec![22, 44, 66];
let vec1 = fill_vec(vec0);
assert_eq!(vec1, [22, 44, 66, 88]);
}
}

struct

..语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#[derive(Debug)]
struct Order {
name: String,
year: u32,
made_by_phone: bool,
made_by_mobile: bool,
made_by_email: bool,
item_number: u32,
count: u32,
}

fn create_order_template() -> Order {
Order {
name: String::from("Bob"),
year: 2019,
made_by_phone: false,
made_by_mobile: false,
made_by_email: true,
item_number: 123,
count: 0,
}
}

fn main() {
// You can optionally experiment here.
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn your_order() {
let order_template = create_order_template();

// TODO: Create your own order using the update syntax and template above!
// let your_order =
let your_order = Order {
name: String::from("Hacker in Rust"),
count: 1,
..order_template
};
assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile);
assert_eq!(your_order.made_by_email, order_template.made_by_email);
assert_eq!(your_order.item_number, order_template.item_number);
assert_eq!(your_order.count, 1);
}
}

enum

enum 可以存放的 variants 类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#[derive(Debug)]
struct Point {
x: u64,
y: u64,
}

#[derive(Debug)]
enum Message {
// TODO: Define the different variants used below.
Resize { width: u32, height: u32 },
Move(Point),
Echo(String),
ChangeColor(u8, u8, u8),
Quit,
}

impl Message {
fn call(&self) {
println!("{self:?}");
}
}

fn main() {
let messages = [
Message::Resize {
width: 10,
height: 30,
},
Message::Move(Point { x: 10, y: 15 }),
Message::Echo(String::from("hello world")),
Message::ChangeColor(200, 255, 255),
Message::Quit,
];

for message in &messages {
message.call();
}
}


string

quiz2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// This is a quiz for the following sections:
// - Strings
// - Vecs
// - Move semantics
// - Modules
// - Enums
//
// Let's build a little machine in the form of a function. As input, we're going
// to give a list of strings and commands. These commands determine what action
// is going to be applied to the string. It can either be:
// - Uppercase the string
// - Trim the string
// - Append "bar" to the string a specified amount of times
//
// The exact form of this will be:
// - The input is going to be a Vector of 2-length tuples,
// the first element is the string, the second one is the command.
// - The output element is going to be a vector of strings.

enum Command {
Uppercase,
Trim,
Append(usize),
}

mod my_module {
use super::Command;

// TODO: Complete the function as described above.
// pub fn transformer(input: ???) -> ??? { ??? }
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
let mut output = vec![];
for (s, cmd) in input.iter() {
match cmd {
Command::Uppercase => {
output.push(s.to_uppercase());
}
Command::Trim => {
output.push(s.trim().to_string());
}
Command::Append(times) => {
output.push(format!("{}{}", s, "bar".repeat(*times)));
}
}
}
output
}
}

fn main() {
// You can optionally experiment here.
}

#[cfg(test)]
mod tests {
// TODO: What do we need to import to have `transformer` in scope?
// use ???;
use super::my_module::transformer;
use super::Command;

#[test]
fn it_works() {
let input = vec![
("hello".to_string(), Command::Uppercase),
(" all roads lead to rome! ".to_string(), Command::Trim),
("foo".to_string(), Command::Append(1)),
("bar".to_string(), Command::Append(5)),
];
let output = transformer(input);

assert_eq!(
output,
[
"HELLO",
"all roads lead to rome!",
"foobar",
"barbarbarbarbarbar",
]
);
}
}

hashmap

entry 方法非常好用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// We're collecting different fruits to bake a delicious fruit cake. For this,
// we have a basket, which we'll represent in the form of a hash map. The key
// represents the name of each fruit we collect and the value represents how
// many of that particular fruit we have collected. Three types of fruits -
// Apple (4), Mango (2) and Lychee (5) are already in the basket hash map. You
// must add fruit to the basket so that there is at least one of each kind and
// more than 11 in total - we have a lot of mouths to feed. You are not allowed
// to insert any more of the fruits that are already in the basket (Apple,
// Mango, and Lychee).

use std::collections::HashMap;

#[derive(Hash, PartialEq, Eq, Debug)]
enum Fruit {
Apple,
Banana,
Mango,
Lychee,
Pineapple,
}

fn fruit_basket(basket: &mut HashMap<Fruit, u32>) {
let fruit_kinds = [
Fruit::Apple,
Fruit::Banana,
Fruit::Mango,
Fruit::Lychee,
Fruit::Pineapple,
];

for fruit in fruit_kinds {
// TODO: Insert new fruits if they are not already present in the
// basket. Note that you are not allowed to put any type of fruit that's
// already present!
basket.entry(fruit).or_insert(8);
}
}

fn main() {
// You can optionally experiment here.
}

#[cfg(test)]
mod tests {
use super::*;

// Don't modify this function!
fn get_fruit_basket() -> HashMap<Fruit, u32> {
let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
HashMap::from_iter(content)
}

#[test]
fn test_given_fruits_are_not_modified() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4);
assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2);
assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5);
}

#[test]
fn at_least_five_types_of_fruits() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
let count_fruit_kinds = basket.len();
assert!(count_fruit_kinds >= 5);
}

#[test]
fn greater_than_eleven_fruits() {
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
let count = basket.values().sum::<u32>();
assert!(count > 11);
}

#[test]
fn all_fruit_types_in_basket() {
let fruit_kinds = [
Fruit::Apple,
Fruit::Banana,
Fruit::Mango,
Fruit::Lychee,
Fruit::Pineapple,
];

let mut basket = get_fruit_basket();
fruit_basket(&mut basket);

for fruit_kind in fruit_kinds {
let Some(amount) = basket.get(&fruit_kind) else {
panic!("Fruit kind {fruit_kind:?} was not found in basket");
};
assert!(*amount > 0);
}
}
}

entry().and_modify().or_insert()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// A list of scores (one per line) of a soccer match is given. Each line is of
// the form "<team_1_name>,<team_2_name>,<team_1_goals>,<team_2_goals>"
// Example: "England,France,4,2" (England scored 4 goals, France 2).
//
// You have to build a scores table containing the name of the team, the total
// number of goals the team scored, and the total number of goals the team
// conceded.

use std::collections::HashMap;

// A structure to store the goal details of a team.
#[derive(Default)]
struct TeamScores {
goals_scored: u8,
goals_conceded: u8,
}

fn build_scores_table(results: &str) -> HashMap<&str, TeamScores> {
// The name of the team is the key and its associated struct is the value.
let mut scores = HashMap::<&str, TeamScores>::new();

for line in results.lines() {
let mut split_iterator = line.split(',');
// NOTE: We use `unwrap` because we didn't deal with error handling yet.
let team_1_name = split_iterator.next().unwrap();
let team_2_name = split_iterator.next().unwrap();
let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();

// TODO: Populate the scores table with the extracted details.
// Keep in mind that goals scored by team 1 will be the number of goals
// conceded by team 2. Similarly, goals scored by team 2 will be the
// number of goals conceded by team 1.
scores
.entry(team_1_name)
.and_modify(|teamscore| {
teamscore.goals_scored += team_1_score;
teamscore.goals_conceded += team_2_score;
})
.or_insert(TeamScores {
goals_scored: team_1_score,
goals_conceded: team_2_score,
});
scores
.entry(team_2_name)
.and_modify(|teamscore| {
teamscore.goals_scored += team_2_score;
teamscore.goals_conceded += team_1_score;
})
.or_insert(TeamScores {
goals_scored: team_2_score,
goals_conceded: team_1_score,
});
}

scores
}

fn main() {
// You can optionally experiment here.
}

#[cfg(test)]
mod tests {
use super::*;

const RESULTS: &str = "England,France,4,2
France,Italy,3,1
Poland,Spain,2,0
Germany,England,2,1
England,Spain,1,0";

#[test]
fn build_scores() {
let scores = build_scores_table(RESULTS);

assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
.into_iter()
.all(|team_name| scores.contains_key(team_name)));
}

#[test]
fn validate_team_score_1() {
let scores = build_scores_table(RESULTS);
let team = scores.get("England").unwrap();
assert_eq!(team.goals_scored, 6);
assert_eq!(team.goals_conceded, 4);
}

#[test]
fn validate_team_score_2() {
let scores = build_scores_table(RESULTS);
let team = scores.get("Spain").unwrap();
assert_eq!(team.goals_scored, 0);
assert_eq!(team.goals_conceded, 3);
}
}

option

match取得所有权,可以用ref声明取得的是ref类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}

fn main() {
let optional_point = Some(Point { x: 100, y: 200 });

// TODO: Fix the compiler error by adding something to this match statement.
match optional_point {
Some(ref p) => println!("Coordinates are {},{}", p.x, p.y),
_ => panic!("No match!"),
}

println!("{optional_point:?}"); // Don't change this line.
}

也可以直接match引用类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}

fn main() {
let optional_point = Some(Point { x: 100, y: 200 });

// TODO: Fix the compiler error by adding something to this match statement.
match &optional_point {
Some(p) => println!("Coordinates are {},{}", p.x, p.y),
_ => panic!("No match!"),
}

println!("{optional_point:?}"); // Don't change this line.
}