Rust 知识积累(5)

发布时间 2023-03-22 21:17:07作者: 摧残一生

&str

字符串
  • 直接声明时,生命周期为整个程序,直接写进了二进制中,类型为&'static str',意为字符串字元有一个叫static的生命期
借用str
  • 作为String的引用来使用,无生命期,例如 fn print_str(my_str: &str){},调用为print_str(&String::format("string""));

生命期

  • 引用的生命期不能比这个对象长

    fn returns_str() -> &str{
        return "I am" // ---错误,因为这个值声明是在方法内,引用出去后是null
    }
    // 改进
    fn returns_str() -> &‘static str{
        return "I am" // ---正确,返回了字符串字面量,该值整个程序有效
    }
    

struct使用

  • 基础使用

    // 尝试写struct City<'a>和name: &'a str
    // 意思是 name可以存活到与City一样的生命期
    // a可以为任意值
    #[derive(Debug)]
    struct City<'a>{
        name: &'a str,
        date_f: u32,
    }
    let my_city = City{
        name: &"China".to_string(),
        date_f: 2022,
    }
    
  • 添加调用方法

    // 不仅仅struct要与name同一个生命期,impl也要一致
    struct Adventurer<'a>{
        name: &'a str,
        hit_points: u32,
    }
    impl Adventer<'_>{
        fn take_damage(&mut self){
            slef.hit_points -= 20;
            println!("{} has {} hit", slef.name, self.hit_points);
        }
    }
    fn main(){
        let mut bi = Adventurer{
            name:"Billy",
            hit_points: 100,
        }
        bi.take_damage();
    }
    

内部可变性

  • 不用mut也可修改数据,例如Cell,RefCell,Mutex, RwLock

  • Cell

    // 给出的是值而不是引用
    use std::cell::Cell;
    struct PhoneModel{
        on_sale: Cell<bool>,
    }
    fn main(){
        let huawei_phone = PhoneModel{
            on_sale: Cell::new(true),
        };
        huawei_phone.on_sale.set(false);
    }
    
  • RefCell

    // 引用单元格,引用
    // 小心使用,他是运行后编译
    use std::cell::RefCell;
    struce User{
        active: RefCell<bool>,
    }
    fn main(){
        let user_l = user{
            active: RefCell::new(true),
        };
        println!("{}", user_l.active);
    
        user_l.active.borrow();
        user_l.active.borrow_mut(); //引出后就不能再borrow_mut()了
        user_l.active.replace(false);
    
    }
    
  • Mutex

    线程安全,只让一个线程修改它(有lock())

    use std::sync::Mutex;
    let my_mutex = Mutex::new(5);
    // 加锁
    let mut mutex_changer = my_mutex.lock().unwarp();
    // 加锁后修改,也可大括号括起来,括号外自己解锁(超出加锁范围)
    *mutex_changer = 6;
    // 解锁
    std::mem::drop(mutex_changer);
    // 判断是否可用
    if let Ok(value) = my_mutex.try_lock(){
        //没加锁
    }else{
        // 加锁
    }
    
    // 直接赋值,不需要解锁
    *my_mutex.lock().unwarp() = 6;
    
  • RwLock

    1. 读写锁 类似于Mutex和RefCell

    2. 多个.read() 可以,一个.write() 可以

    use std::sync::RwLock;
    let my_rwlock = RwLock::new(5);
    let read1 = my_rwlock.read().unwrap(); // 多个read都可以
    let read2 = my_rwlock.read().unwrap();// 多个read都可以
    drop(read1); 
    drop(read2); // 两个read()都进行了解锁,因此可以write()
    let mut write1 = my_rwlock.write().unwarp();
    *write1 = 6;
    drop(write1); // 解锁后可继续操作
    
    if let Ok(mut number) = my_rwlock.try_write(){
        *number += 10
    }else{
        // 锁住了
    }
    

Cow

  • 枚举,写时克隆

    // 说明: 当类型为B时,返回 Borrowed(&'a B), 否则 Owned(<B as ToOwned>:Owned)
    pub enum Cow<'a, B> where B: 'a + ToOwned + ?Size,{
        Borrowed(&'a B),
        Owned(<B as ToOwned>:Owned),
    }
    // Cow<'static, str>判断时为
    // Cow::Borrowed(message) : message 为 实际值
    // Cow::Owned(message) : message 为 实际值
    //注意,返回的数值是str
    fn modulo_3(input: u8) -> Cow<'static, str> {
        match input % 3 {
            0 => "Remainder is 0".into(),
            1 => "Remainder is 1".into(),
            remainder => format!("Remainder is {}", remainder).into(), // 这个为String,因此会变成Cow::Owned()
        }
    }
    
    fn main() {
        for number in 1..=6 {
            match modulo_3(number) {
                Cow::Borrowed(message) => println!("{} went in. The Cow is borrowed with this message: {}", number, message),
                Cow::Owned(message) => println!("{} went in. The Cow is owned with this message: {}", number, message),
            }
        }
    }
    

类型别名

  • 声明别名的几种方式及使用

    //方式一
    type CharacterVec = Vec<char>;
    //方式二
    type SkipFourTakeFive<'a> = std::iter::Take<std::iter::Skip<std::slice::Iter<'a, char>>>;
    fn returns<'a>(input: &'a Vec<char>) -> SkipFourTakeFive {
        input.iter().skip(4).take(5)
    }
    //方式三
    use std::iter::{Task, Skip};
    use std::slice::Iter;
    fn returns<'a>(input: &'a Vec<char>) -> Take<Skip<Iter<'a, char>>> {
        input.iter().skip(4).take(5)
    }
    //方式四
    struct File(String); // File is a wrapper around String
    
    fn main() {
        let my_file = File(String::from("I am file contents"));
        let my_string = String::from("I am file contents");
        println!("{}", my_file == my_string);  // ⚠️ 错误,不能比较,因为类型不对
        println!("{}", my_file.0 == my_string);//      正确
    }
    //方式五 enum枚举简单调用
    enum MapDirection{
        North, East,
    }
    fn main(){
        use MapDirection::*;
        //后面可直接使用 MapDirction
        match direction{
            North => println!(),
            East => println!();
        }
        // 也可以进行改名
        use MapDirection::{
            North as N,
            East as E,
        }
    }
    

todo! 宏

  • 还未想好如何操作,但是又要运行,可以用 todo!()

    fn get_book(book: &Book) -> Option<String> {
        todo!() // todo means "I will do it later, please be quiet"
    }
    

Rc

  • 使用数量变为0,才会消失

    use std::rc:Rc;
    let history = Rc::new("".to_string());
    let h2 = history.clone() // Rc的计数变为了2
    println!("{}", Rc::strong_count(&history)); //强引用数量
    Rc::downgrade(&item) 来创建弱引用 //如果只有弱引用,则变量会消失
    Rc::weak_count(&item) 查看弱引用数
    

多线程

  • std ::thread ::spawn 创建线程

    fn main(){
        //当主程序结束,线程还未结束时,会报异常
        std::thread::spawn(||{
            println!("");
        });
        // 改进 将线程绑定到变量上
        let handle = std::thread::spawn(||{
            println!("");
        });
        handle.join();
        
        // 取值
        let mut my_str = String::form("");
        let handle = std::thread::spawn(move || { // 使用move来获得线程外的数值
            println!("{}", my_str);
        });
        handle.join();
    }
    

闭包

  • FnOnce: 取整个值

  • FnMut : 取一个可变引用

  • Fn : 取一个普通引用

  • 各种方式举例

    // fn方式
    let my_str = String::form("string");
    let my_closure = || println!("{}", my_str);
    my_closure();   //可多次调用    
    my_closure(); // String没有实现copy,因此是Fn
    
    // FnMut方式
    let mut my_str = String::form("string");
    let mut my_closure = || {
        my_str.push_str(" clone");
        println!("{}", my_str);
    }
    my_closure();   //可多次调用,my_str会新增clone字符串
    my_closure();   // 如果改变my_str, 就变成了FnMut
    
    //  FnOnce方式
    let my_vec: Vec<i32> = vec![8, 9, 10];
    let my_closure = || {
        my_vec
        .into_iter() // into_iter takes ownership
        .map(|x| x as u8) // turn it into u8
        .map(|x| x * 2) // multiply by 2
        .collect::<Vec<u8>>() // collect into a Vec
    };
    let new_vec = my_closure(); //只能使用一次