一直想学习第二语言奈何一直没动力,前几天正好看到博主讨论所谓的计算机”三大浪漫“,其实之前也有尝试过实现编程语言,当然现在也正在进行中,在这位博主里了解到了实现一个tcp协议可能比三大浪漫更能提升个人水平,所以就想借这个机会用Rust去实现这个项目。如果较真的话,JS才应该算是我的第二语言,第一语言应该是C# (话说不应该是C吗) ,毕竟是通过学Unity才正式进入编程领域的,只是后面因为种种原因放弃了Unity转而专心学习JS。

如果不是零基础学rust的话,建议直接从官方项目入手: minigrep,遇到不会的概念往前翻手册即可,直接跳过漫长枯燥的基础学习期。


Hello World

无论之前学过几门语言、学的如何,所写的新语言的第一句代码应该像新生儿的第一句啼哭一样,永远是hello world

1
2
3
fn main(){
println!("Hello World!");
}

fmt

Display

自定义输出格式

1

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
use std::fmt; // Import `fmt`

// A structure holding two numbers. `Debug` will be derived so the results can
// be contrasted with `Display`.
#[derive(Debug)]
struct MinMax(i64, i64);

// Implement `Display` for `MinMax`.
impl fmt::Display for MinMax {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Use `self.number` to refer to each positional data point.
write!(f, "({}, {})", self.0, self.1)
}
}

// Define a structure where the fields are nameable for comparison.
#[derive(Debug)]
struct Point2D {
x: f64,
y: f64,
}

// Similarly, implement `Display` for `Point2D`.
impl fmt::Display for Point2D {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Customize so only `x` and `y` are denoted.
write!(f, "x: {}, y: {}", self.x, self.y)
}
}

fn main() {
let minmax = MinMax(0, 14);

println!("Compare structures:");
println!("Display: {}", minmax);
println!("Debug: {:?}", minmax);

let big_range = MinMax(-300, 300);
let small_range = MinMax(-3, 3);

println!(
"The big range is {big} and the small is {small}",
small = small_range,
big = big_range
);

let point = Point2D { x: 3.3, y: 7.2 };

println!("Compare points:");
println!("Display: {}", point);
println!("Debug: {:?}", point);

// Error. Both `Debug` and `Display` were implemented, but `{:b}`
// requires `fmt::Binary` to be implemented. This will not work.
// println!("What does Point2D look like in binary: {:b}?", point);
}

2

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
use std::fmt::{self, Display, Formatter};

struct City {
name: &'static str,
// Latitude
lat: f32,
// Longitude
lon: f32,
}
impl Display for City {
// `f` is a buffer, and this method must write the formatted string into it.
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let lat_c = if self.lat >= 0.0 { 'N' } else { 'S' };
let lon_c = if self.lon >= 0.0 { 'E' } else { 'W' };

// `write!` is like `format!`, but it will write the formatted string
// into a buffer (the first argument).
write!(
f,
"{}: {:.3}°{} {:.3}°{}",
self.name,
self.lat.abs(),
lat_c,
self.lon.abs(),
lon_c
)
}
}

#[derive(Debug)]
struct Color {
red: u8,
green: u8,
blue: u8,
}

impl Display for Color {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let hex: u32 =
(self.red as u32 * 65_536 as u32) + (self.green as u32 * 256 as u32) + self.blue as u32;

write!(
f,
"RGB ({}, {}, {}) 0X{:06X}",
self.red, self.green, self.blue, hex
)
}
}

fn main() {
for city in [
City {
name: "Dublin",
lat: 53.347778,
lon: -6.259722,
},
City {
name: "Oslo",
lat: 59.95,
lon: 10.75,
},
City {
name: "Vancouver",
lat: 49.25,
lon: -123.1,
},
] {
println!("{}", city);
}
for color in [
Color {
red: 128,
green: 255,
blue: 90,
},
Color {
red: 0,
green: 3,
blue: 254,
},
Color {
red: 0,
green: 0,
blue: 0,
},
] {
// Switch this to use {} once you've added an implementation
// for fmt::Display.
println!("{}", color);
}
}

Structures

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
// An attribute to hide warnings for unused code.
#![allow(dead_code)]

#[derive(Debug)]
struct Person {
name: String,
age: u8,
}

// A unit struct
struct Unit;

// A tuple struct
struct Pair(i32, f32);

// A struct with two fields
struct Point {
x: f32,
y: f32,
}

// Structs can be reused as fields of another struct
struct Rectangle {
// A rectangle can be specified by where the top left and bottom right
// corners are in space.
top_left: Point,
bottom_right: Point,
}

fn main() {
// Create struct with field init shorthand
let name = String::from("Peter");
let age = 27;
let peter = Person { name, age };

// Print debug struct
println!("{:?}", peter);

// Instantiate a `Point`
let point: Point = Point { x: 5.2, y: 0.4 };
let another_point: Point = Point { x: 10.3, y: 0.2 };

// Access the fields of the point
println!("point coordinates: ({}, {})", point.x, point.y);

// Make a new point by using struct update syntax to use the fields of our
// other one
let bottom_right = Point {
x: 10.3,
..another_point
};

// `bottom_right.y` will be the same as `another_point.y` because we used that field
// from `another_point`
println!("second point: ({}, {})", bottom_right.x, bottom_right.y);

// Destructure the point using a `let` binding
let Point {
x: left_edge,
y: top_edge,
} = point;

let _rectangle = Rectangle {
// struct instantiation is an expression too
top_left: Point {
x: left_edge,
y: top_edge,
},
bottom_right: bottom_right,
};

// Instantiate a unit struct
let _unit = Unit;

// Instantiate a tuple struct
let pair = Pair(1, 0.1);

// Access the fields of a tuple struct
println!("pair contains {:?} and {:?}", pair.0, pair.1);

// Destructure a tuple struct
let Pair(integer, decimal) = pair;

println!("pair contains {:?} and {:?}", integer, decimal);
}

Enums

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
// Create an `enum` to classify a web event. Note how both
// names and type information together specify the variant:
// `PageLoad != PageUnload` and `KeyPress(char) != Paste(String)`.
// Each is different and independent.
enum WebEvent {
// An `enum` variant may either be `unit-like`,
PageLoad,
PageUnload,
// like tuple structs,
KeyPress(char),
Paste(String),
// or c-like structures.
Click { x: i64, y: i64 },
}

// A function which takes a `WebEvent` enum as an argument and
// returns nothing.
fn inspect(event: WebEvent) {
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
// Destructure `c` from inside the `enum` variant.
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
// Destructure `Click` into `x` and `y`.
WebEvent::Click { x, y } => {
println!("clicked at x={}, y={}.", x, y);
}
}
}

fn main() {
let pressed = WebEvent::KeyPress('x');
// `to_owned()` creates an owned `String` from a string slice.
let pasted = WebEvent::Paste("my text".to_owned());
let click = WebEvent::Click { x: 20, y: 80 };
let load = WebEvent::PageLoad;
let unload = WebEvent::PageUnload;

inspect(pressed);
inspect(pasted);
inspect(click);
inspect(load);
inspect(unload);
}

Break

break可用于赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() {
let mut counter = 0;

let result = loop {
counter += 1;

if counter == 10 {
break counter * 2;
}
};

assert_eq!(result, 20);
}

Ownership

所有权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
fn main() {
let names = vec!["Bob", "Frank", "Ferris"];

for name in names.into_iter() {
match name {
"Ferris" => println!("There is a rustacean among us!"),
_ => println!("Hello {}", name),
}
}

println!("names: {:?}", names);
// FIXME ^ Comment out this line

}

Destructuring

tuples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fn main() {
let triple = (0, -2, 3);
// TODO ^ Try different values for `triple`

println!("Tell me about {:?}", triple);
// Match can be used to destructure a tuple
match triple {
// Destructure the second and third elements
(0, y, z) => println!("First is `0`, `y` is {:?}, and `z` is {:?}", y, z),
(1, ..) => println!("First is `1` and the rest doesn't matter"),
(.., 2) => println!("last is `2` and the rest doesn't matter"),
(3, .., 4) => println!("First is `3`, last is `4`, and the rest doesn't matter"),
// `..` can be used to ignore the rest of the tuple
_ => println!("It doesn't matter what they are"),
// `_` means don't bind the value to a variable
}
}

array

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
fn main() {
// Try changing the values in the array, or make it a slice!
let array = [1, -2, 6];

match array {
// Binds the second and the third elements to the respective variables
[0, second, third] => println!("array[0] = 0, array[1] = {}, array[2] = {}", second, third),

// Single values can be ignored with _
[1, _, third] => println!(
"array[0] = 1, array[2] = {} and array[1] was ignored",
third
),

// You can also bind some and ignore the rest
[-1, second, ..] => println!(
"array[0] = -1, array[1] = {} and all the other ones were ignored",
second
),
// The code below would not compile
// [-1, second] => ...

// Or store them in another array/slice (the type depends on
// that of the value that is being matched against)
[3, second, tail @ ..] => println!(
"array[0] = 3, array[1] = {} and the other elements were {:?}",
second, tail
),

// Combining these patterns, we can, for example, bind the first and
// last values, and store the rest of them in a single array
[first, middle @ .., last] => println!(
"array[0] = {}, middle = {:?}, array[2] = {}",
first, middle, last
),
}
}