RUST学习3

Debug

The Debug trait enables us to print our struct in a way that is useful for developers so we can see its value while we’re debugging our code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[derive(Debug)]  //开启使用debug :?打印结构体
struct Rectangle {
width: u32,
height: u32,
}

fn main() {
let rect1 = Rectangle {
width: 30,
height: 50,
};

println!("rect1 is {:?}", rect1); //or{:#?}
}

method

their first parameter is always self, which represents the instance of the struct the method is being called on.

impl (implementation)

Methods can take ownership of self, borrowself immutablyas we’ve done here, or borrow self mutably, just as they can any other parameter.
&mut self

associated function

You’ve already used the String::from associated function.

Associated functions are often used for constructors that will return a new instance of the struct.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}

impl Rectangle {
fn square(size: u32) -> Rectangle { //没有self
Rectangle {
width: size,
height: size,
}
}
}

fn main() {
let sq = Rectangle::square(3);
}

Each struct is allowed to have multiple impl blocks.

Enum

枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum IpAddrKind {
V4, //V4 V6就是所谓的变体
V6,
}

fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;

route(IpAddrKind::V4);
route(IpAddrKind::V6);
}

fn route(ip_kind: IpAddrKind) {}

枚举比struct更简明

1
2
3
4
5
6
7
8
9
10
11
fn main() {
enum IpAddr {
V4(String),
V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));

let loopback = IpAddr::V6(String::from("::1"));
}

枚举每个变体可以有不同的类型

1
2
3
4
5
6
7
8
9
10
11
fn main() {
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);

let loopback = IpAddr::V6(String::from("::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
[allow(unused_variables)]
fn main() {
struct Ipv4Addr {
// --snip--
}

struct Ipv6Addr {
// --snip--
}

enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
}

enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}


fn main() {
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}

impl Message {
fn call(&self) {
// method body would be defined here
}
}

let m = Message::Write(String::from("hello"));
m.call();
}

enum option

1
2
3
4
5
6
7
![allow(unused_variables)]
fn main() {
enum Option<T> { //<T> means the Some variant of the Option enum can hold one piece of data of any type
Some(T),
None,
}
}

option不用显示引入,已经提前有了

1
2
3
4
5
6
fn main() {
let some_number = Some(5);
let some_string = Some("a string");

let absent_number: Option<i32> = None;
}

If we use None rather than Some, we need to tell Rust what type of Option<T> we have
Option and T (where T can be any type) are different types,
In other words, you have to convert an Option to a T before you can perform T operations with it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
match
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}

fn main() {}

The code associated with each arm is an expression, and the resulting value of the expression in the matching arm is the value that gets returned for the entire match expression.

1
2
3
4
5
6
7
8
9
10
11
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
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

[derive(Debug)]
enum UsState {
Alabama,
Alaska,
// --snip--
}

enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state); //得到coin里quarter里的usstate值
25
}
}
}

fn main() {
value_in_cents(Coin::Quarter(UsState::Alaska));
}

使用option

1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() {
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}

let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}

Combining match and enums is useful in many situations.
match against an enum, bind a variable to the data inside, and then execute code based on it.

1
2
3
4
5
6
7
8
9
10
fn main() {
let some_u8_value = 0u8;
match some_u8_value {
1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
7 => println!("seven"),
_ => (),
}
}

_省略The _ pattern will match any value.The () is just the unit value

if let

care about only one of the cases. For this situation, Rust provides if let.

1
2
3
4
5
6
7
fn main() {
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
}

1
2
3
4
5
6
7
8
9
fn main() {
let coin = Coin::Penny;
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}
}
1
2
3
4
5
6
7
8
9
10

fn main() {
let coin = Coin::Penny;
let mut count = 0;
match coin {
Coin::Quarter(state) => println!("State quarter from {:?}!", state),
_ => count += 1,
}
}

packages>crates>modules

A package isone or more cratesthat provide a set of functionality. A package contains a Cargo.toml file that describes how to build those crates.
A package must contain zero or one library crates, and no more. It can contain as many binary crates as you’d like, but it must contain at least one crate (either library or binary).
If a package contains src/main.rs and src/lib.rs, it has two crates: a library and a binary, both with the same name as the package.
A package canhave multiple binary crates by placing files in the src/bin directory:each file will be a separate binary crate.

the use keyword that brings a path into scope; and the pub keyword to make items public. We’ll also discuss the as keyword, external packages, and the glob operator

Modules let us organize code within a crate into groups

Create a new library named restaurant by running cargo new --lib restaurant;
crate //implicit module src/main.rs and src/lib.rs 产生
└── front_of_house
├── hosting
│ ├── add_to_waitlist
│ └── seat_at_table
└── serving
├── take_order
├── serve_order
└── take_payment

If we want to call a function, we need to know its path.
A path can take two forms:

An absolute path starts from a crate root by using a crate name or a literal crate.
A relative path starts from the current module and uses self, super, or an identifier in the current module.
Both absolute and relative paths are followed by one or more identifiers separated by double colons (::).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
}
}

pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();

// Relative path
front_of_house::hosting::add_to_waitlist();
}

The way privacy works in Rust is that all items (functions, methods, structs, enums, modules, and constants) are private by default.

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
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {} //making the module public doesn’t make its contents public.
}
}

pub fn eat_at_restaurant() {
// Absolute path
crate::front_of_house::hosting::add_to_waitlist();

// Relative path
front_of_house::hosting::add_to_waitlist();
}


fn serve_order() {}

mod back_of_house {
fn fix_incorrect_order() {
cook_order();
super::serve_order();
}

fn cook_order() {}
}

Enums aren’t very useful unless their variants are public; it would be annoying to have to annotate all enum variants with pub in every case, so the default for enum variants is to be public. Structs are often useful without their fields being public, so struct fields follow the general rule of everything being private by default unless annotated with pub.

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
use
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

use crate::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}

mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

use self::front_of_house::hosting;

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}

fn main() {}

as

There’s another solution to the problem of bringing two types of the same name into the same scope with use: after the path, we can specify as and a new local name, or alias, for the type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
![allow(unused_variables)]
fn main() {
use std::fmt::Result;
use std::io::Result as IoResult;

fn function1() -> Result {
// --snip--
Ok(())
}

fn function2() -> IoResult<()> {
// --snip--
Ok(())
}
}

this technique is called re-exporting because we’re bringing an item into scope but also making that item available for others to bring into their scope

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}

pub use crate::front_of_house::hosting; //其他可以 另外创立一个链接

pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}

fn main() {}

fn main() {
use std::collections::HashMap;
}

This is an absolute path starting with std, the name of the standard library crate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

use rand::Rng;
// --snip--
use std::{cmp::Ordering, io};
// --snip--


fn main() {
use std::io::{self, Write};
}

#![allow(unused_variables)]
fn main() {
use std::collections::*;
}

brings all public items

The mod keyword declares modules, and Rust looks in a file with the same name as the module for the code that goes into that module.

vector

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
let v: Vec<i32> = Vec::new();
}

fn main() {
let v = vec![1, 2, 3]; //类别自己推测
}
fn main() {
let mut v = Vec::new();

v.push(5);
v.push(6);
v.push(7);
v.push(8);
}
fn main() {
{
let v = vec![1, 2, 3, 4];

// do stuff with v
} // <- v goes out of scope and is freed here
}

1
2
3
4
5
6
7
8
9
10
11
12
fn main() {
let v = vec![1, 2, 3, 4, 5];

let third: &i32 = &v[2];
println!("The third element is {}", third);

match v.get(2) { //gives us an Option<&T>.
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
}

1
2
3
4
5
6
fn main() {
let mut v = vec![100, 32, 57];
for i in &mut v {
*i += 50; //解引用 dereference operator (*) to get to the value in i
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
fn main() {
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}

let row = vec![ //vec类型为SpreadsheetCell 实际上存储不同类型值
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
}

枚举要配合match使用

string

Remember thatstrings are UTF-8encoded,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fn main() {
let hello = String::from("السلام عليكم");
let hello = String::from("Dobrý den");
let hello = String::from("Hello");
let hello = String::from("שָׁלוֹם");
let hello = String::from("नमस्ते");
let hello = String::from("こんにちは");
let hello = String::from("안녕하세요");
let hello = String::from("你好");
let hello = String::from("Olá");
let hello = String::from("Здравствуйте");
let hello = String::from("Hola");
}

fn main() {
let mut s = String::from("foo");
s.push_str("bar");
}

fn main() {
let mut s = String::from("lo");
s.push('l');
}

push method takesa single character

1
2
3
4
5
fn main() {
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//be moved into the add call and no longer be valid after that.
}

add is that the compiler can coerce the &String argument into a &str

format

1
2
3
4
5
6
7
fn main() {
let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");

let s = format!("{}-{}-{}", s1, s2, s3); //doesn’t take ownership of any of its parameters.
}

utf-8 可变字节 1-4字节,有些一个字节 有些4个字节

1
2
3
4
5
6
[allow(unused_variables)]
fn main() {
let hello = "Здравствуйте";

let s = &hello[0..4];
}
1
2
3
4
5
6
#![allow(unused_variables)]
fn main() {
for c in "नमस्ते".chars() {
println!("{}", c);
}
}
1
2
3
4
5
6
7
#![allow(unused_variables)]
fn main() {
for b in "नमस्ते".bytes() { // returns each raw byte,
println!("{}", b);
}
}

hashmap

all of the keys must have the same type, and all of thevaluesmust have the same type.

1
2
3
4
5
6
fn main() {
use std::collections::HashMap;
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);
}
1
2
3
4
5
6
7
8
9
fn main() {
use std::collections::HashMap;

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

let mut scores: HashMap<_, _> =
teams.into_iter().zip(initial_scores.into_iter()).collect();
}

zip method to create a vector of tuples
collect method to turn that vector of tuples into a hash map,

For types that implement the Copy trait, like i32, the values are copied into the hash map. For owned values like String, the values will be moved and the hash map will be the owner of those values

1
2
3
4
5
6
7
8
9
10
11
fn main() {
use std::collections::HashMap;

let mut scores = HashMap::new();

scores.insert(String::from("Blue"), 10);
scores.insert(String::from("Yellow"), 50);

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

Some(&10). The result is wrapped in Some because get returns an Option<&V>
no value get will return None.

for (key, value) in &scores {
    println!("{}: {}", key, value);
}
1
2
3
4
5
6
7
8
9
10
11
12

fn main() {
use std::collections::HashMap;

let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);

scores.entry(String::from("Yellow")).or_insert(50); //entry检查值是否存在,返回Entry, or_insert是Entry的方法 return a mutable reference to the value 没有值插入
scores.entry(String::from("Blue")).or_insert(50);

println!("{:?}", scores); //{"Yellow": 50, "Blue": 10}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() {
use std::collections::HashMap;

let text = "hello world wonderful world";

let mut map = HashMap::new();

for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0); //or_insert method actually returns a mutable reference (&mut V) 所以可以加1
*count += 1;
}

println!("{:?}", map);
}