Rust随笔

Cargo

  1. New
1
cargo new hello_cargo --bin
  1. Build
    default mode: debug.
    file path: target/debug.
1
cargo build --release
  1. Check
1
cargo check
  1. Run
1
cargo run

Comon Concepts

Main

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

Import

1
2
3
4
extern crate rand;

use std::io;
use rand::Rng;

Variables

1
2
3
let foo = 5; // immutable
let mut bar = 5; // mutable
const MAX_POINTS: u32 = 100_000; //constants, must declare with data type

Shadowing

Shadowing a mut can modify its data type, difference from reassigning to a mut.

1
2
3
4
5
6
let x = 5;
let x = x + 1;

//error
let mut spaces = " ";
spaces = spaces.len();

Data Types

Scalar Types

Integer Types
Length Signed Unsigned
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
arch isize usize

Integer Literals in Rust

Number literals Example
Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
Byte (u8 only) b’A’

Floating-Point Types

Rust’s floating-point types are f32 and f64 (default).

Boolean Type

The Boolean type in Rust is specified using bool, Boolean type in Rust has two possible values: true and false.

Compound Types

Tuple Type

1
2
3
4
let tup: (i32, f64, u8) = (500, 6.4, 1);
let tup = (500, 6.4, 1);
let (x, y, z) = tup;
let five_hundred = x.0;

Array Type

1
2
let a = [1, 2, 3, 4, 5];
let first = a[0];

Functions

Rust code uses snake case as the conventional style for function and variable names.

Statements are instructions that perform some action and do not return a value.
Expressions evaluate to a resulting value.

The type of returned values need to be declared after an arrow (->). In Rust, the return value of the function is synonymous with the value of the final expression in the block of the body of a function. You can also return early from a function by using the return keyword.

1
2
3
fn plus_one(x: i32) -> i32 {
x + 1
}

Comments

In Rust, comments must start with two slashes and continue until the end of the line. For comments that extend beyond a single line, you’ll need to include // on each line.

Control Flow

if

if expression’s condition don’t need “()” and all arms should have types that are compatible.

1
2
3
4
5
6
7
let a = if number % 4 == 0 {
4
} else if number % 3 == 0 {
3
} else {
0
}

loops

Rust has three kinds of loops: loop, while, and for.
loop has no conditions and run forever until break.

1
2
3
4
5
fn main() {
loop {
println!("again!");
}
}

while has an condition like if.

1
2
3
while number != 0 {
number = number - 1;
}

for is specially for iteration.

1
2
3
for element in [1,2].iter() {
println!("the value is: {}", element);
}

Ownership

reference

1
2
3
fn calculate_length(s: &mut String) -> usize {
s.len()
}

slice

1
2
3
4
5
6
7
let s = String::from("hello world");

let hello = &s[0..5]; // Type: &str
let all = &s[..];

let a = [1, 2, 3];
let slice = &a[1..3]; // Type: &[i32]

Struct

struct is like class in rust. With impl blocks, you can define struct’s method. (Each struct is allowed to have multiple impl blocks.)

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
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}

let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};

user1.email = String::from("anotheremail@example.com");

let user2 = User {
email: String::from("another@example.com"),
username: String::from("anotherusername567"),
..user1
};

//tuple struct
struct Color(i32, i32, i32);

let black = Color(0, 0, 0);
let a = black.1;

//unit-like strutc
struct Point;

//impl
struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}

fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
let sq = Rectangle::square(3);

Enum and Pattern Matching

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

//match block
let black = match message {
Message::Quit => 1,
Message::Move{..} => 2,
Message::ChangeColor(_, y, _) => {
y
},
_ => 0,
};

//if let block
if let Message::Quit = message {
1
} else {
0
}

Modules

Rules of Module Filesystems

  • If a module named foo has no submodules, you should put the declarations for foo in a file named foo.rs.
  • If a module named foo does have submodules, you should put the declarations for foo in a file named foo/mod.rs.

Privacy Rules

  • An item (mods or functions in mod) is private unless set to pub.
  • If an item is public, it can be accessed through any of its parent modules.
  • If an item is private, it can be accessed only by its immediate parent module and any of the parent’s child modules.

Referring to Names in Different Modules

The use keyword brings only what we’ve specified into scope: it does not bring children of modules into scope.
To bring all the items in a namespace into scope at once, we can use the * syntax, which is called the glob operator.
Use super to access a parent module, or use leading colons to start from the root and list the whole path.

1
2
::client::connect();
super::client::connect();

Common Collections

Vectors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let v: Vec<i32> = Vec::new();
v.push(5);

let v = vec![1, 2, 3];

let third: &i32 = &v[2];
let third: Option<&i32> = v.get(2);

for i in &v {
println!("{}", i);
}

for i in &mut v {
*i += 50;
}

String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let mut s = String::new();
let s = "initial contents".to_string();
let s = String::from("initial contents");

let mut s = String::from("foo");
s.push_str("bar");


let s1 = String::from("Hello, ");
let s2 = String::from("world!");
let s3 = s1 + &s2; // note s1 has been moved here and can no longer be used

let s = format!("{}-{}", s2, s3);

for c in "中文".chars() {
println!("{}", c);
}

Hash Map

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
use std::collections::HashMap;

let mut scores = HashMap::new();

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
scores.entry(String::from("Blue")).or_insert(50);//inserting a Value if the key has no value

let team_name = String::from("Blue");
let score = scores.get(&team_name);

//zip
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];

let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect(); // HashMap<_, _> is needed here because it’s possible to collect into many different data structures and Rust doesn’t know which you want unless you specify.

//ownship
let field_name = String::from("Favorite color");
let field_value = String::from("Blue");

let mut map = HashMap::new();
map.insert(field_name, field_value);
// field_name and field_value are invalid at this point, try using them and
// see what compiler error you get!

//iteration
for (key, value) in &scores {
println!("{}: {}", key, value);
}