Rust入门


1.安装

官网 https://www.rust-lang.org/learn/get-started

2.猜数字游戏

use std::io;
use rand::{thread_rng, Rng};
use std::cmp::Ordering;

fn main() {
    let secret_num = thread_rng().gen_range(1, 101);
    loop {
        println!("请猜一个数:");
    
        let mut guess = String::new();
        io::stdin().read_line(&mut guess).expect("无法读取");
        println!("您猜的数字是:{}",guess);

        let guess:u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue  
        };

        match guess.cmp(&secret_num){
            Ordering::Less => println!("Too small"),
            Ordering::Equal => {
                println!("you win!");
                break;
            },
            Ordering::Greater => println!("Too big"),
        }
    }
    
}

3.编程概念

3.1 变量可变性

fn main() {
    let x = 5;
    println!("The value of x is: {x}");
    x = 6;//报错,变量如果要修改需要用mut修饰
    println!("The value of x is: {x}");
}
//常量声明
const THREE_HOURS_IN_SECONDS: u32 = 60 * 60 * 3;
//可以重复声明变量,后面的声明的变量覆盖前面的
let spaces = "   ";
let spaces = spaces.len();

3.2数据类型

3.2.1 整数

Rust 有四种主要标量类型:整数、浮点数、布尔值和字符。

长度 签名 未签名
8位 i8 u8
16位 i16 u16
32位 i32 u32
64位 i64 u64
128位 i128 u128
数字字面量 例子
十进制 98_222
十六进制 0xff
八进制 0o77
二进制 0b1111_0000
字节 b'A'

3.2.2 浮点数

fn main() {
    let x = 2.0; // f64

    let y: f32 = 3.0; // f32
}

3.2.3 布尔类型

fn main() {
    let t = true;

    let f: bool = false; // with explicit type annotation
}

3.2.4 字符类型

fn main() {
    let c = 'z';
    let z: char = 'ℤ'; // with explicit type annotation
    let heart_eyed_cat = '😻';
}

3.2.5 元组

fn main() {
    let tup: (i32, f64, u8) = (500, 6.4, 1);
}
fn main() {
    let tup = (500, 6.4, 1);

    let (x, y, z) = tup;

    println!("The value of y is: {y}");
}
fn main() {
    let x: (i32, f64, u8) = (500, 6.4, 1);
	//取值
    let five_hundred = x.0;

    let six_point_four = x.1;

    let one = x.2;
}

3.2.6 数组

当知道元素数量不需要更改时,数组会更有用。例如,如果您在程序中使用月份名称,您可能会使用数组而不是向量,因为您知道它始终包含 12 个元素:

let months = ["January", "February", "March", "April", "May", "June", "July",
              "August", "September", "October", "November", "December"];

可以使用方括号、每个元素的类型、分号以及数组中元素的数量来编写数组的类型,如下所示:

let a: [i32; 5] = [1, 2, 3, 4, 5];

这里,i32是每个元素的类型。分号后面的数字5 表示数组包含五个元素。

还可以通过指定初始值、后跟分号、然后在方括号中指定数组的长度来初始化数组,使其每个元素包含相同的值,如下所示:

let a = [3; 5];

指定的数组a将包含5所有元素,这些元素将全部设置为 3最初的值。这与写作相同let a = [3, 3, 3, 3, 3];,但方式更简洁。

fn main() {
    let a = [1, 2, 3, 4, 5];
	//访问数组中的值
    let first = a[0];
    let second = a[1];
}

3.3函数

3.3.1 函数的参数

fn main() {
    another_function(5);
}

//必须声明参数的类型
fn another_function(x: i32) {
    println!("The value of x is: {x}");
}

3.3.2 有返回值参数

fn main() {
    let x = plus_one(5);

    println!("The value of x is: {x}");
}

fn plus_one(x: i32) -> i32 {
    //默认返回值不用写分号,如果要提前返回则用return 返回值;
    x + 1
}

3.4流程控制

3.4.1 if和else

fn main() {
    let number = 6;

    if number % 4 == 0 {
        println!("number is divisible by 4");
    } else if number % 3 == 0 {
        println!("number is divisible by 3");
    } else if number % 2 == 0 {
        println!("number is divisible by 2");
    } else {
        println!("number is not divisible by 4, 3, or 2");
    }
}
fn main() {
    let condition = true;
	//条件赋值
    let number = if condition { 5 } else { "six" };

    println!("The value of number is: {number}");
}

3.4.2 loop循环

fn main() {
    let mut counter = 0;
	//带返回值
    let result = loop {
        counter += 1;

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

    println!("The result is {result}");
}

3.4.3 while循环

fn main() {
    let mut number = 3;

    while number != 0 {
        println!("{number}!");

        number -= 1;
    }

    println!("LIFTOFF!!!");
}

3.4.4 for循环

fn main() {
    let a = [10, 20, 30, 40, 50];

    for element in a {
        println!("the value is: {element}");
    }
}
fn main() {
    for number in (1..4).rev() {
        println!("{number}!");
    }
    println!("LIFTOFF!!!");
}

4.所有权

4.1 所有权规则

  • Rust 中的每个值都有一个所有者
  • 一次只能有一位所有者。
  • 当所有者超出范围时,该值将被删除。
fn main() {
    let mut s = String::from("hello");

    s.push_str(", world!"); // push_str() appends a literal to a String

    //将s变量的值更换所有者为s1,更换后s将被销毁
    let s1 = s;
    println!("{s1}"); 
    
    {
        //将s1的值克隆一份给s2
        let s2 = s1.clone();
        println!("{s2}"); 
    }
    println!("{s1}"); 
}

4.2 变量不移动类型

let x = 5;
let y = x;

println!("x = {x}, y = {y}");

没有调用 clone,但x仍然有效并且没有移入y,该类型具有自动copy的特征

具有copy特征的类型

  • 所有整数类型,例如u32.
  • 布尔类型 ,bool具有值truefalse
  • 所有浮点类型,例如f64.
  • 字符类型,char.
  • 元组,如果它们仅包含也实现Copy.例如, (i32, i32)实现Copy,但(i32, String)不实现。

4.3 引用

4.3.1 不可变引用

fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{s1}' is {len}.");
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

4.3.2 可变引用

fn main() {
    let mut s = String::from("hello");

    change(&mut s);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

同一域内不可出现多个可变引用,但可出现多个不可变引用

4.3.3 悬空引用

fn main() {
    let reference_to_nothing = dangle();
}

fn dangle() -> &String {
    let s = String::from("hello");
	//当代码dangle完成时,s将会被释放。但我们试图返回对它的引用。这意味着该引用将指向无效的String,故此处会报错
    &s
}

解决办法如下

fn no_dangle() -> String {
    let s = String::from("hello");

    s
}

4.4 切片

4.4.1 字符串切片

//切片参数为&str
fn first_word(s: &str) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn main() {
    let my_string = String::from("hello world");

    // `first_word` works on slices of `String`s, whether partial or whole
    let word = first_word(&my_string[0..6]);
    println!("{}",word);
    let word = first_word(&my_string[..]);
    // `first_word` also works on references to `String`s, which are equivalent
    // to whole slices of `String`s
    let word = first_word(&my_string);
    println!("{}",word);

    let my_string_literal = "hello world";

    // `first_word` works on slices of string literals, whether partial or whole
    let word = first_word(&my_string_literal[0..6]);
    println!("{}",word);
    let word = first_word(&my_string_literal[..]);
    println!("{}",word);
    // Because string literals *are* string slices already,
    // this works too, without the slice syntax!
    let word = first_word(my_string_literal);
    println!("{}",word);
}

4.4.2 其他切片

fn main() {
    let a = [1, 2, 3, 4, 5];

    let slice = &a[1..3];

    assert_eq!(slice, &[2, 3]);
}

5.结构体

5.1 定义


#[derive(Debug)]
struct User {
    active: bool,
    username: String,
    email: String,
    sign_in_count: u64,
}

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

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

    println!("{:#?}",user1);
}
//元组方式定义
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

fn main() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);
}

5.2 方法语法

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

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

impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width > other.width && self.height > other.height
    }
}

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

    println!(
        "The area of the rectangle is {} square pixels.",
        rect1.area()
    );

    let rect2 = Rectangle {
        width: 10,
        height: 40,
    };
    let rect3 = Rectangle {
        width: 60,
        height: 45,
    };

    println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
    println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}

6.枚举

6.1 定义

#[derive(Debug)]
enum IpAddr {
    V4(String),
    V6(String),
}

fn main() {

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

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

    println!("{:#?}",home)
}

6.2 方法

#[derive(Debug)]
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
        println!("{:?}", self);
    }
}

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

6.3 枚举Option

fn main() {
    let x: i8 = 5;
    let y: Option<i8> = Some(5);
    //let y: Option<i8> = None;

    if y.is_none() {
        println!("y is None");
        return;
    }
    let sum = x + y.unwrap();
    println!("Sum: {}", sum);
}

6.4 match

fn plus_one(x: Option<i32>) -> Option<i32> {
    match x {
        //None => None,
        Some(i) => Some(i + 1),
        //需要涵盖所有可能性
        _=> None
    }
}

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

6.5 if let

enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn main() {
    let mut count = 0;
    let coin= Coin::Quarter;
    if let Coin::Quarter = coin {
        println!("this is quarter!");
    } else {
        count += 1;
    }
}
fn main() {
    let config_max = Some(3);
    if let Some(max) = config_max {
        println!("The maximum is configured to be {max}");
    }
}

7.自定义模块

创建模块

cargo new restaurant --lib

执行命令后会生成

└─restaurant
    │  Cargo.toml
    │
    └─src
            lib.rs

在lib.rs中写入

pub mod front_of_house {
    //仅仅pub修饰的才可被外部调用
    pub mod hosting {
        pub fn add_to_waitlist() {
            println!("excute add_to_waitlist!");
        }

        fn seat_at_table() {}
    }

    mod serving {
        fn take_order() {}

        fn serve_order() {}

        fn take_payment() {}
    }
}

在最外层main方法中调用

//引入
include!("restaurant/src/lib.rs");

use front_of_house::hosting;

fn main() {
    // Relative path
    hosting::add_to_waitlist();
}

模块内容分文件存放

模块定义时,如果模块名后边是“;”,而不是代码块:

  • Rust会从与模块同名的文件中加载内容
  • 模块树的结构不会变化

随着模块逐渐变大,该技术让你可以把模块的内容移动到其它文件中

8.集合

8.1 vector

fn main() {
    //使用Vec<T>创建一个新的空Vec<T>实例
    let v: Vec<i32> = Vec::new();
    //使用vec!宏创建一个包含特定值的Vec<T>实例
    let v = vec![1, 2, 3];

    //更新Vec<T>的值
    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, 5];

    //这种方式会导致panic
    let does_not_exist = &v[100];
    //这种方式会返回None
    let does_not_exist = v.get(100);

}
fn main() {
    let mut v = vec![1, 2, 3, 4, 5];

    let first = &v[0];

    //会报错,因为v.push(6)会导致内存重新分配,first指向的内存已经被释放
    v.push(6);

    println!("The first element is: {first}");

}
fn main() {
    let mut v = vec![100, 32, 57];
    //遍历
    for i in &mut v {
        *i += 50;
    }

}
fn main() {
    enum SpreadsheetCell {
        Int(i32),
        Float(f64),
        Text(String),
    }
    //使用枚举来储存不同类型的数据
    let row = vec![
        SpreadsheetCell::Int(3),
        SpreadsheetCell::Text(String::from("blue")),
        SpreadsheetCell::Float(10.12),
    ];

}

8.2 HashMap

use std::collections::HashMap;

fn main() {
    let mut scores = HashMap::new();

    // 插入键值对
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Yellow"), 50);

    let team_name = String::from("Blue");
    // 通过get方法获取值,如果存在则返回Some,否则返回None
    let score = scores.get(&team_name).copied().unwrap_or(0);

    // 通过for循环遍历HashMap
    for (key, value) in &scores {
        println!("{key}: {value}");
    }

    //更新值
    scores.insert(String::from("Blue"), 10);
    scores.insert(String::from("Blue"), 25);

    // 如果键对应的值不存在,则插入,否则更新
    scores.entry(String::from("Blue")).or_insert(50);
    
}
use std::collections::HashMap;

fn main() {
    //统计字符串中单词出现的次数

    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);
        *count += 1;
    }

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

9.错误处理

9.1 立即终止配置

Cargo.toml文件中添加

[profile.release]
panic = 'abort'

9.2 回溯环境变量

RUST_BACKTRACE=1 cargo run

设置RUST_BACKTRACE环境变量来获取导致错误的确切原因的回溯。回溯是为达到这一点而调用的所有函数的列表

9.3 match匹配Result

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let greeting_file_result = File::open("hello.txt");

    let greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => fc,
                Err(e) => panic!("Problem creating the file: {e:?}"),
            },
            other_error => {
                panic!("Problem opening the file: {other_error:?}");
            }
        },
    };
}

优化后

use std::fs::File;
use std::io::ErrorKind;

fn main() {
    let greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("hello.txt").unwrap_or_else(|error| {
                panic!("Problem creating the file: {error:?}");
            })
        } else {
            panic!("Problem opening the file: {error:?}");
        }
    });
}

9.4 unwrap和expect

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt").unwrap();
}
use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt")
        .expect("hello.txt should be included in this project");
}

9.5 函数中错误传播

use std::fs::File;
use std::io::{self, Read};

fn read_username_from_file() -> Result<String, io::Error> {
    //使用?返回错误
    let mut username_file = File::open("hello.txt")?;
    let mut username = String::new();
    username_file.read_to_string(&mut username)?;
    Ok(username)
}

10.泛型、特征和生命周期

10.1 泛型

10.1.1 函数定义泛型

//PartialOrd is a trait that allows comparison between values of the same type.
fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];

    for item in list {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];

    let result = largest(&number_list);
    println!("The largest number is {result}");

    let char_list = vec!['y', 'm', 'a', 'q'];

    let result = largest(&char_list);
    println!("The largest char is {result}");
}

10.1.2 结构体中定义泛型

struct Point<T, U> {
    x: T,
    y: U,
}

fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_float = Point { x: 5, y: 4.0 };
}
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };

    println!("p.x = {}", p.x());
}

10.1.3 枚举中定义泛型

struct Point<X1, Y1> {
    x: X1,
    y: Y1,
}

impl<X1, Y1> Point<X1, Y1> {
    fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}

fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c' };

    let p3 = p1.mixup(p2);

    println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}

10.2 特征

在lib.rs中写入

pub trait Summary {
    fn summarize(&self) -> String;
}

pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

// Implementing the Summary trait on the NewsArticle struct
impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

// Implementing the Summary trait on the Tweet struct
impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

在main.rs中调用

use hello::{Summary, Tweet};


fn main() {
    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from(
            "of course, as you probably already know, people",
        ),
        reply: false,
        retweet: false,
    };

    println!("1 new tweet: {}", tweet.summarize());
}

作为参数使用

use std::fmt::{Display, Debug};

fn some_function<T, U>(t: &T, u: &U) -> i32
//use the where keyword to specify that both T must implement Display and Clone trait and U must implement Clone and Debug trait
where
    T: Display + Clone,
    U: Clone + Debug,
{
    1
}

10.3 生命周期

生命周期是我们已经使用过的另一种泛型。生命周期不是确保类型具有我们想要的行为,而是确保引用在我们需要的时间内有效。

//'a is a lifetime annotation
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}
fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {result}");
}
// 'static is a lifetime annotation, which means that this reference can live for the entire duration of the program.
let s: &'static str = "I have a static lifetime.";

11.自动化测试

$ cargo new adder --lib
     Created library `adder` project
$ cd adder

在src/lib.rs中会自动生成

pub fn add(left: usize, right: usize) -> usize {
    left + right
}

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

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }
}

执行cargo test命令可进行测试

12.命令行程序案例

需求:输入命令 xx.exe query filename从文件中查找包含query的文本,并打印出来

lib.rs

use std::env;

pub struct Args {
    filename: String,
    query: String,
    case_sensitive: bool
}

impl Args {
    pub fn new(args: &[String]) -> Result<Args, &'static str> {
        if args.len() < 3 {
            return Err("not enough arguments");
        }
        let filename = args[2].clone();
        let query = args[1].clone();
        //获取环境变量
        let case_sensitive = env::var("CASE_SENSITIVE").is_ok();
        Ok(Args { filename, query , case_sensitive: case_sensitive})
    }
    
}

pub fn run(config: Args) -> Result<(), std::io::Error> {
    let contents = std::fs::read_to_string(config.filename)?;
    if config.case_sensitive {
        search(&config.query, &contents);
    } else {
        search_case_insensitive(&config.query, &contents);
    }
    Ok(())
}

pub fn search(query: &str, contents: &str) {
    //filter returns an iterator
    let result: Vec<String> = contents.lines().filter(|line| line.contains(query)).map(|s| s.to_string()).collect();
    println!("{:?}", result);
}

pub fn search_case_insensitive(query: &str, contents: &str) {
    let query = query.to_lowercase();
    let result: Vec<String> = contents.lines().filter(|line| line.to_lowercase().contains(&query)).map(|s| s.to_string()).collect();
    println!("{:?}", result);
}

main.rs

use std::env;
use hello::{run, Args};

fn main() {
    let args:Vec<String> = env::args().collect();    
    let args = Args::new(&args).unwrap_or_else(|err| {
        eprintln!("Problem parsing arguments: {}", err);
        std::process::exit(1);
    });
    if let Err(e) = run(args){
        eprintln!("Application error: {}", e);
        std::process::exit(1);
    };

}

13.闭包

13.1 定义闭包

fn main() {
    let mut list = vec![1, 2, 3];
    println!("Before defining closure: {list:?}");

    //相当于定义一个函数
    let mut borrows_mutably = || list.push(7);

    //执行
    borrows_mutably();
    println!("After calling closure: {list:?}");
}

13.2 转让所有权给闭包

use std::thread;

fn main() {
    let list = vec![1, 2, 3];
    println!("Before defining closure: {list:?}");

    //move关键字表示将list的所有权转移给闭包
    thread::spawn(move || println!("From thread: {list:?}"))
        .join()
        .unwrap();
}

13.3 排序

#[derive(Debug)]
struct Rectangle {
    width: u32,
    height: u32,
}

fn main() {
    let mut list = [
        Rectangle { width: 10, height: 1 },
        Rectangle { width: 3, height: 5 },
        Rectangle { width: 7, height: 12 },
    ];

    let mut num_sort_operations = 0;
    //sort_by_key is a method of the Iterator trait
    list.sort_by_key(|r| {
        num_sort_operations += 1;
        r.width
    });
    println!("{list:#?}, sorted in {num_sort_operations} operations");
}

13.4 迭代器

fn main() {
    let v1: Vec<i32> = vec![1, 2, 3];

    //map returns an iterator
    let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();

    assert_eq!(v2, vec![2, 3, 4]);
    println!("{:?}", v2);
}

14.智能指针

14.1 使用Box在堆上存储数据

fn main() {
    let b = Box::new(5);
    println!("b = {b}");
}

14.2 自定义智能指针

struct MyBox<T>(T);

use std::ops::Deref;

impl<T> Deref for MyBox<T> {
    type Target = T;

    // deref 方法返回一个引用,这样 * 运算符就可以使用在 MyBox<T> 值上了
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
fn main() {
    let x = 5;
    let y = MyBox::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);

}

14.3 drop使用

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    // Drop trait is used to run some code when a value goes out of scope
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}

14.4 引用计数智能指针

enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};
use std::rc::Rc;

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    //统计引用计数,结果为1
    println!("count after creating a = {}", Rc::strong_count(&a));
    let b = Cons(3, Rc::clone(&a));
    //统计引用计数,结果为2
    println!("count after creating b = {}", Rc::strong_count(&a));
    {
        let c = Cons(4, Rc::clone(&a));
        //统计引用计数,结果为3
        println!("count after creating c = {}", Rc::strong_count(&a));
    }
    //统计引用计数,结果为2
    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

14.5 内部可变指针

pub trait Messenger {
    fn send(&self, msg: &str);
}

//定义触发器结构体
pub struct LimitTracker<'a, T: Messenger> {
    messenger: &'a T,
    value: usize,
    max: usize,
}

impl<'a, T> LimitTracker<'a, T>
where
    T: Messenger,
{
    pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {
        LimitTracker {
            messenger,
            value: 0,
            max,
        }
    }

    //设置触发器的值
    pub fn set_value(&mut self, value: usize) {
        self.value = value;

        let percentage_of_max = self.value as f64 / self.max as f64;

        if percentage_of_max >= 1.0 {
            self.messenger.send("Error: You are over your quota!");
        } else if percentage_of_max >= 0.9 {
            self.messenger
                .send("Urgent warning: You've used up over 90% of your quota!");
        } else if percentage_of_max >= 0.75 {
            self.messenger
                .send("Warning: You've used up over 75% of your quota!");
        }
    }
}

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

    //定义消息结构体
    struct MockMessenger {
        //RefCell<T>是一个智能指针,它允许在运行时而不是在编译时检查借用规则
        sent_messages: RefCell<Vec<String>>,
    }

    impl MockMessenger {
        fn new() -> MockMessenger {
            MockMessenger {
                sent_messages: RefCell::new(vec![]),
            }
        }
    }

    impl Messenger for MockMessenger {
        //发送消息
        fn send(&self, message: &str) {
            //RefCell<T>的borrow_mut方法返回RefMut<T>智能指针类型,它记录了运行时借用检查
            self.sent_messages.borrow_mut().push(String::from(message));
            println!("{}", message);
        }
    }

    #[test]
    fn it_sends_an_over_75_percent_warning_message() {
        let mock_messenger = MockMessenger::new();
        let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);

        limit_tracker.set_value(80);
        assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
    }
}

14.6 使用弱引用解决循环引用导致的内存泄漏问题

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
struct Node {
    value: i32,
    //parent字段是一个可变弱引用,用于指向父节点
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        //初始化一个Weak指针,指向一个空的Node
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!(
        "leaf strong = {}, weak = {}",
        //结果是1和0,因为leaf是唯一的Rc指针,没有其他指针指向它
        Rc::strong_count(&leaf),
        Rc::weak_count(&leaf),
    );

    {
        let branch = Rc::new(Node {
            value: 5,
            parent: RefCell::new(Weak::new()),
            children: RefCell::new(vec![Rc::clone(&leaf)]),
        });

        *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

        println!(
            "branch strong = {}, weak = {}",
            //结果是1和1,因为branch是唯一的Rc指针,但有一个Weak指针指向它
            Rc::strong_count(&branch),
            Rc::weak_count(&branch),
        );

        println!(
            "leaf strong = {}, weak = {}",
            //结果是2和0,因为leaf有两个Rc指针指向它
            Rc::strong_count(&leaf),
            Rc::weak_count(&leaf),
        );
    }

    //branch离开作用域后,leaf的唯一Rc指针被销毁
    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
    println!(
        "leaf strong = {}, weak = {}",
        //结果是1和0,因为branch离开作用域后,leaf的唯一Rc指针被销毁
        Rc::strong_count(&leaf),
        Rc::weak_count(&leaf),
    );
}

15.并发

15.1 多线程


use std::thread;
use std::time::Duration;

fn main() {
    // Creating a new thread
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {i} from the spawned thread!");
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {i} from the main thread!");
        thread::sleep(Duration::from_millis(1));
    }

    // Wait for the spawned thread to finish
    handle.join().unwrap();
}

15.2 与move一起使用

use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    //move closure takes ownership of v
    let handle = thread::spawn(move || {
        println!("Here's a vector: {v:?}");
    });

    handle.join().unwrap();
}

15.3 线程间数据共享

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("hi");
        //执行send方法后,val的所有权被转移给了接收者,所以这里不能再使用val
        tx.send(val).unwrap();
        //println!("val is {val}");
    });

    let received = rx.recv().unwrap();
    println!("Got: {received}");
}
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

//多个消息发送者
fn main() {
    let (tx, rx) = mpsc::channel();

    // Cloning the transmitter to send it to another thread
    let tx1 = tx.clone();
    thread::spawn(move || {
        let vals = vec![
            String::from("hi"),
            String::from("from"),
            String::from("the"),
            String::from("thread"),
        ];

        for val in vals {
            tx1.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    thread::spawn(move || {
        let vals = vec![
            String::from("more"),
            String::from("messages"),
            String::from("for"),
            String::from("you"),
        ];

        for val in vals {
            tx.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    for received in rx {
        println!("Got: {received}");
    }
}

15.4 线程间状态共享

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    //Arc是一个原子引用计数类型,可以安全的在线程间共享数据,mutex是一个互斥锁,可以保证在同一时刻只有一个线程访问数据
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

16.模式和匹配

16.1 if let

fn main() {
    let favorite_color: Option<&str> = None;
    let is_tuesday = false;
    let age: Result<u8, _> = "34".parse();

    if let Some(color) = favorite_color {
        println!("Using your favorite color, {color}, as the background");
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        //这里会执行两次匹配,第一次匹配age是否是Ok,第二次匹配age的值是否大于30,结果是age的值是34,所以会输出Using purple as the background color
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}

16.2 while let

fn main() {
    let mut stack = Vec::new();

    stack.push(1);
    stack.push(2);
    stack.push(3);

    //结果是3 2 1
    while let Some(top) = stack.pop() {
        println!("{top}");
    }
}

16.3 if let

fn main() {
    let v = vec!['a', 'b', 'c'];

    for (index, value) in v.iter().enumerate() {
        println!("{value} is at index {index}");
    }
}

16.4 可反驳性

函数参数、let语句和for循环只能接受无可辩驳的模式,因为当值不匹配时程序无法执行任何有意义的操作。if letand表达式while let接受可反驳和不可反驳的模式,但编译器会警告不可反驳的模式,因为根据定义,它们旨在处理可能的失败:条件的功能在于其能够根据成功或失败执行不同的操作。

16.5 模式语法

16.5.1 配置值

fn main() {
    let x = 1;

    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}

16.5.2 匹配命名变量

fn main() {
    let x = Some(5);
    let y = 10;

    match x {
        Some(50) => println!("Got 50"),
        //匹配到Some(y)时,将y的值绑定到y变量
        Some(y) => println!("Matched, y = {y}"),
        _ => println!("Default case, x = {x:?}"),
    }

    println!("at the end: x = {x:?}, y = {y}");

    //Matched, y = 5
    //at the end: x = Some(5), y = 10
}

16.5.3 多种模式

fn main() {
    let x = 1;

    match x {
        1 | 2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}

16.5.4 匹配返回

fn main() {
    let x = 5;

    match x {
        // 1..=5 is a range pattern that matches any number from 1 through 5
        1..=5 => println!("one through five"),
        _ => println!("something else"),
    }
}

16.5.5 解构

struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: 0, y: 7 };

    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);
}

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

fn main() {
    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.");
        }
        Message::Move { x, y } => {
            println!("Move in the x direction {x} and in the y direction {y}");
        }
        Message::Write(text) => {
            println!("Text message: {text}");
        }
        Message::ChangeColor(r, g, b) => {
            println!("Change the color to red {r}, green {g}, and blue {b}")
        }
    }
}

16.5.6 忽略值

fn foo(_: i32, y: i32) {
    println!("This code only uses the y parameter: {y}");
}

fn main() {
    foo(3, 4);
}
fn main() {
    struct Point {
        x: i32,
        y: i32,
        z: i32,
    }

    let origin = Point { x: 0, y: 0, z: 0 };

    match origin {
        //忽略剩余的字段
        Point { x, .. } => println!("x is {x}"),
    }
}

16.5.7 match额外条件

fn main() {
    let num = Some(4);

    match num {
        //匹配Some中的值,如果是偶数则打印
        Some(x) if x % 2 == 0 => println!("The number {x} is even"),
        Some(x) => println!("The number {x} is odd"),
        None => (),
    }
}

17.高级特性

17.1 原始指针

fn main() {
    let mut num = 5;

    //创建原始指针
    let r1 = &num as *const i32;
    let r2 = &mut num as *mut i32;

    println!("r1: {:p}", r1);
    println!("r1: {:p}", r2);
}

17.2 不安全代码块中执行不安全方法

fn main() {
    unsafe fn dangerous() {println!("dangerous function");}

    unsafe {
        dangerous();
    }
}

use std::slice;

fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
    let len = values.len();
    let ptr = values.as_mut_ptr();

    assert!(mid <= len);

    // The slice::from_raw_parts_mut function is unsafe because it can create aliased mutable references.
    unsafe {
        (
            // slice::from_raw_parts_mut(ptr, mid) is equivalent to &mut values[..mid]
            slice::from_raw_parts_mut(ptr, mid),
            // slice::from_raw_parts_mut(ptr.add(mid), len - mid) is equivalent to &mut values[mid..]
            slice::from_raw_parts_mut(ptr.add(mid), len - mid),
        )
    }
}

fn main() {
    let mut v = vec![1, 2, 3, 4, 5, 6];

    let r = &mut v[..];

    let (a, b) = split_at_mut(r,3);

    assert_eq!(a, &mut [1, 2, 3]);
    assert_eq!(b, &mut [4, 5, 6]);
}

17.3 使用extern函数调用外部代码

extern "C" {
    // This is the C function that we want to call
    fn abs(input: i32) -> i32;
}

fn main() {
    unsafe {
        // Call the C function
        println!("Absolute value of -3 according to C: {}", abs(-3));
    }
}

17.4 C语言调用rust

#[no_mangle]
pub extern "C" fn call_from_c() {
    println!("Just called a Rust function from C!");
}

17.5 修改静态变量

static mut COUNTER: u32 = 0;

fn add_to_count(inc: u32) {
    unsafe {
        COUNTER += inc;
    }
}

fn main() {
    add_to_count(3);

    unsafe {
        println!("COUNTER: {COUNTER}");
    }
}

17.6 不安全trait

//定义一个 unsafe trait
unsafe trait Foo {
    fn foo(&self);
}

unsafe impl Foo for i32 {
    //实现foo方法
    fn foo(&self) {
        println!("Hello, world!");
    }
}

fn main() {
    let x = 42;
    //在unsafe块中调用foo方法
    unsafe {
        x.foo();
    }
}

17.7 默认运算符重载

use std::ops::Add;

#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

fn main() {
    assert_eq!(
        Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
        Point { x: 3, y: 3 }
    );
}
use std::ops::Add;

struct Millimeters(u32);
struct Meters(u32);

impl Add<Meters> for Millimeters {
    type Output = Millimeters;

    fn add(self, other: Meters) -> Millimeters {
        Millimeters(self.0 + (other.0 * 1000))
    }
}


fn main() {
    let m = Millimeters(10) + Meters(1);
    println!("{}", m.0);
}

17.8 调用同名方法

trait Animal {
    fn baby_name() -> String;
}

struct Dog;

impl Dog {
    fn baby_name() -> String {
        String::from("Spot")
    }
}

impl Animal for Dog {
    fn baby_name() -> String {
        String::from("puppy")
    }
}

fn main() {
    //调用Dog的baby_name方法
    println!("A baby dog is called a {}", Dog::baby_name());
    //调用Animal的baby_name方法
    print!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}

17.9 trait继承

use std::fmt;

//该trait继承了fmt::Display,所以我们可以使用to_string方法
trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {output} *");
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}
struct Point {
    x: i32,
    y: i32,
}

impl OutlinePrint for Point {}

//必须实现fmt::Display
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Point { x: 1, y: 2 };
    p.outline_print();
}

17.10 包装

//这是一个包装器类型,它包含一个 Vec<String>。我们想要实现 fmt::Display 来打印这个包装器类型,但是 Vec<T> 并不实现 fmt::Display。因此,Vec<T> 也不满足打印的要求。
struct Wrapper(Vec<String>);

impl fmt::Display for Wrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}]", self.0.join(", "))
    }
}

fn main() {
    let w = Wrapper(vec![String::from("hello"), String::from("world")]);
    println!("w = {w}");
}

17.11 类型别名

fn main() {
    //类型别名
    type Kilometers = i32;

    let x: i32 = 5;
    let y: Kilometers = 5;

    println!("x + y = {}", x + y);
}
fn main() {
    //定义类型别名来减少重复
    type Thunk = Box<dyn Fn() + Send + 'static>;

    let f: Thunk = Box::new(|| println!("hi"));

    //使用类型别名
    fn takes_long_type(f: Thunk) {
        // --snip--
    }

    fn returns_long_type() -> Thunk {
        Box::new(|| println!("hi"))
    }
}

17.12 永不反回类型

Rust 有一种特殊类型!,在类型理论术语中称为 空类型,因为它没有值。我们更喜欢将其称为never 类型 ,因为当函数永远不会返回时,它代表返回类型。

fn bar() -> ! {
    // --snip--
}

17.13 函数指针

fn add_one(x: i32) -> i32 {
    x + 1
}

//参数是一个函数
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {answer}");
}
fn main() {
    let list_of_numbers = vec![1, 2, 3];
    //传入一个闭包
    let list_of_strings: Vec<String> =
        list_of_numbers.iter().map(|i| i.to_string()).collect();
        println!("{:?}", list_of_strings);

    let list_of_numbers = vec![1, 2, 3];
    //传入一个函数
    let list_of_strings: Vec<String> =
    list_of_numbers.iter().map(ToString::to_string).collect();
    println!("{:?}", list_of_strings);
}

17.14 返回特征类型

//返回特征对象,不能直接返回闭包,因为闭包类型是匿名的
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}

fn main() {
    let closure = returns_closure();
    println!("{}", closure(5));
}

18.多线程web服务器案例

18.1 定义线程池和线程

//lib.rs
use std::{
    sync::{mpsc, Arc, Mutex},
    thread,
};

pub struct ThreadPool {
    //定义一个Worker结构体的数组
    workers: Vec<Worker>,
    //定义一个Option类型的mpsc::Sender<Job>,用于发送Job
    sender: Option<mpsc::Sender<Job>>,
}

type Job = Box<dyn FnOnce() + Send + 'static>;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        //创建size个Worker结构体,并将其放入workers数组中
        for id in 0..size {
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }

        ThreadPool {
            workers,
            sender: Some(sender),
        }
    }

    pub fn execute<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);

        //将job发送给Worker
        self.sender.as_ref().unwrap().send(job).unwrap();
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        drop(self.sender.take());

        for worker in &mut self.workers {
            println!("Shutting down worker {}", worker.id);

            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    id: usize,
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {

        //创建一个新的线程,用于接收Job
        let thread = thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv();

            match message {
                Ok(job) => {
                    println!("Worker {id} got a job; executing.");

                    job();
                }
                Err(_) => {
                    println!("Worker {id} disconnected; shutting down.");
                    break;
                }
            }
        });

        Worker {
            id,
            thread: Some(thread),
        }
    }
}

18.2 创建返回的html

hello.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello!</title>
  </head>
  <body>
    <h1>Hello!</h1>
    <p>Hi from Rust</p>
  </body>
</html>

404.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello!</title>
  </head>
  <body>
    <h1>Oops!</h1>
    <p>Sorry, I don't know what you're asking for.</p>
  </body>
</html>

18.3 在main方法中实现web服务器

use hello::ThreadPool;
use std::{
    fs,
    io::{prelude::*, BufReader},
    net::{TcpListener, TcpStream},
    thread,
    time::Duration,
};

fn main() {
    let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
    //创建一个线程池,线程数为4
    let pool = ThreadPool::new(4);

    for stream in listener.incoming().take(2) {
        let stream = stream.unwrap();

        //将stream放入线程池中
        pool.execute(|| {
            handle_connection(stream);
        });
    }

    println!("Shutting down.");
}

fn handle_connection(mut stream: TcpStream) {
    let buf_reader = BufReader::new(&stream);
    let request_line = buf_reader.lines().next().unwrap().unwrap();

    let (status_line, filename) = match &request_line[..] {
        "GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"),
        "GET /sleep HTTP/1.1" => {
            thread::sleep(Duration::from_secs(5));
            ("HTTP/1.1 200 OK", "hello.html")
        }
        _ => ("HTTP/1.1 404 NOT FOUND", "404.html"),
    };

    let contents = fs::read_to_string(filename).unwrap();
    let length = contents.len();

    let response =
        format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");

    stream.write_all(response.as_bytes()).unwrap();
    
}