Rust

/ / 4230浏览

前段时间学习了Rust程序语言, 感觉非常棒, 尽管写起来很难受, 但是不得不说, Rust还是非常棒的一门语言.

Rust总结

  1. to_string(),into(), to_owned(),from(), 其背后都是使用 to_owned() , 把数据复制到堆中, 成为自己的数据.

  2. 对于 str 和 String, 判空可使用 val.len() == 0 判断

  3. type的一种用法: 将自定义异常引入Struct的作用域, impl块中可以使用 type = Error的方式引入

  4. 关键字: dyn 用法如: let inner: Option<&(dyn Error + 'static)> = err.source(); 含义为: impl traitdyn trait 区别在于静态分发和动态分发, 且dyn可以指定函数实现多个边界

  5. trait FromStr: 该特征用于将字符串生成特定结构体, type Err是转换时的错误信息, 函数fn from_str(s: &str) -> Result<Self, Self::Err>;是具体定义的转换过程, 返回实现该trait目标对象

  6. Rust 对于数据权限的核心规则, 对于给定的对象T, 只能有以下之一, 否则编译不通过:

    • 对象有几个不可变的引用(&T),也称为别名(aliasing)

    • 对象有一个可变引用(&mut T),也称为可变性(mutability)

  7. 指针 std::boxd::Box: 最基础的指针指针, 由于Rust结构声明时, 必须指定全部的内存类型, 对于某些无法确定到底使用多少内存的场景(比如递归), 需用到, 例子:

    use std::boxd::Box;
    
    #[drive(Debug)]
    enum List<T> {
        Cons(T, Box<List<T>>),    //递归
        Nil,
    }
    
    fn test_box() {
        let val: u8 = 5;
        let boxed: Box<u8> = Box::new(val);    //初始化
        let _: u8 = *boxed;    //解引用
    
        let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
        println!("{:?}", list);        //打印 --- Cons(1, Cons(2, Nil))
    }
    
  8. 指针std::rc::Rc: 单线程引用计数指针. 调用 rc.clone() 会将引用计数加一, 并且不消耗源指针. 对于循环引用, 可以使用Weak版本获取弱引用指针.

  9. 指针std::sync::Arc: 线程安全的引用计数指针. 由于实现了Send traid, 故在多线程中可以安全访问.

  10. 指针std::cell::{Cell, RefCell}, 适用于单线程, 前者 Cell通过将值移出移入原始值进行改变, RefCell通过引用获取内部可变锁从而更改值, RefCell通过内部方法 borrow()try_borrow()获取原始值的可变引用.

  11. 指针std::sync::{RwLock,Mutex}, 适用于多线程 使用内部方法 lock()try_lock() 获取内部可变值

  12. Option枚举

    1. 内部方法 option.take() 可将option内部的值换出来, 放入一个None枚举类型, 可用于获取内部值的所有权, 实际上方法内部调用的还是 std::mem::replace 方法, 调用take方法要求调用者为可变引用.
    2. 内部方法 option.as_ref()|option.as_mut() 可将类型&Option 换为 Option<&T>, 一般用作返回内部引用值使用, 而as_mut()方法可以获取内部可变引用, 之后可以通过内部方法option.map() 更改内部值, 例如:
     //来自 Rust 原始文档
    // as_ref()
    let text: Option<String> = Some("Hello, world!".to_string());
    let text_length: Option<usize> = text.as_ref().map(|s| s.len());    //该处map使用 &String, 不会消耗原始值
    println!("still can print text: {text:?}, text_length: {text_length:?}");
    
    // as_mut()
    let mut x = Some(1);    // 这里使用基本类型而不使用String 为栗子. (是因为String类型没有实现Copy trait) ????
    x.as_mut().map(|value| {
      *value = 100
    });
    assert_eq!(x, Some(100));
    
3. 内部方法 `options.map()` 将一个Option<T> 换为 另外一个 Option<T> , 例如上面的例子中, 将Option中的1 换为 100, 例子中的闭包入参使用的是模式匹配, 如果使用入参 `&mut value` 那value匹配的就是值, 而不是可变引用, 而更改引用内容, 必须使用 **可变引用**, 用value匹配即可.
  1. 生命周期[消除原则]

    1. 每一个引用参数都会获得独自的生命周期. 例如:

      fn foo<'a>(x: &'a i32)
      fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
      
    2. 若只有一个输入生命周期(函数参数中只有一个引用类型),那么该生命周期会被赋给所有的输出生命周期, 例如:

      fn foo(x: &i32) -> &i32
      //等同于
      fn foo<'a>(x: &'a i32) -> &'a i32
      
    3. 若存在多个输入生命周期,且其中一个是 &self&mut self,则 &self 的生命周期被赋给所有的输出生命周期.

---- 持续更新中...