Rust指针:一个变量在内存中包含的是一个地址(即指向其他数据)。
介绍
Rust 中最常见的指针就是 引用:
引用
智能指针
智能指针是这样的一些数据结构:
- 行为和指针类似
- 有额外的元数据和功能
- 很多时候拥有它所指向的数据
智能指针示例:String、Vec<T>,特点如下:
- 都拥有一块内存,且允许用户对其操作
- 都拥有元数据,如容量等
- 提供额外的功能或保障(String 保障其数据是合法的 UTF-8 编码)
智能指针的实现:通常使用 struct 实现,并且实现如下 trait:
- Deref trait:允许智能指针 struct 的实例像引用一样使用
- Drop trait:允许自定义当智能指针实例走出作用域时的代码
引用技术(reference counting)智能指针类型
- 通过记录所有者的数量,使一份数据被多个所有者同时持有
- 当没有任何所有者持有数据时,自动清理数据
标准库中常见的智能指针:
Box<T>
- Box<T>:最简单的只能指针,它被定义成拥有一个元素的- tuple struct- 
- 在 heap 内存上存储数据
- stack 存储指向 heap 数据的指针
- 没有性能开销和其他额外的功能
- 使用场景:
- 大数据量时,想移交所有权,但需要确保在操作时数据不会被复制
- 编译时,某类型的大小无法确定
 
 
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
}
fn main() {
    let x: Box<i32> = Box::new(5);
    println!("x={}", x);
    let x:i32 = 2;
    let y: &i32 = &x;
    let z: Box<i32> = Box::new(x);
    assert_eq!(2, x);
    assert_eq!(2, *y);
    assert_eq!(2, *z);
    let z: MyBox<i32> = MyBox::new(2);
    assert_eq!(2, *z);
}
Deref trait
- Deref解引用
- Deref trait可以自定义解引用运算符- *的行为
- 实现 Deref trait(需要实现deref方法),智能指针可以像常规引用一样来处理
- 实现后,会被隐式的转化为 *(x.deref())
 
函数和方法的 隐式解引用转化(deref coercion)
- 隐式解引用转化(deref coercion)是为函数和方法提供的一种便捷特性
- 若 T 实现了 deref trait,则deref coercion可把 T 的引用转化为 T 经过 deref 操作后生成的引用
- 当把某类型的引用传递给函数或方法时,但它的类型与定义的类型不匹配:
- deref coercion会自动发生
- 编译器会对 deref 进行一系列调用(编译时完成,没有额外性能开销),将其转化为所需的参数类型
 
如:示例中的 MyBox<String> 的引用可以隐式解引用为 &str
- &x: &MyBox<String> -> deref &String -> deref &str
- $x -> &(*mybox)[..]
解引用和可变引用
- 可以使用 DerefMut trait重载可变引用的*运算符
- 在类型和 trait 在下列三种情况发生时,Rust会执行 deref coercion
- 当 T: Deref<Target=U>,允许&T转化为&U
- 当 T: DerefMut<Target=U>,允许&mut T转化为&mut U
- 当 T: Deref<Target=U>,允许&mut T转化为&U
 
Drop trait
- Drop trait可以让自定义当值将要离开作用域时发生的动作,如:关闭文件、网络资源释放等
- 任何类型都可以实现 Drop trait,需要实现drop方法,Drop trait在预导入模块里(prelude)导入
- Drop trait的- drop方法不允许手动调用(但可以调用- std::mem::drop()函数提前手动释放),释放处理时自动清理
#[derive(Debug)]
struct CustomPointer {
    data: String,
}
impl Drop for CustomPointer {
    fn drop(&mut self) {
        println!("data is {}", self.data)
    }
}
fn main() {
    let c: CustomPointer = CustomPointer{ data: String::from("abcd") };
    println!("{:?}", c);
    // drop(c);
}
Rc<T>
- Rc<T>:启用多重所有权的引用计数智能指针类型,通过不可变引用,使程序在不同部分之间共享只读数据- 
- rc 是 reference counting的缩写
- 一个值会有多个所有者
- 追踪所有值的引用
- 当 0 个引用时,该值可以被清理掉
- Rc<T>不在预导入模块(prelude),需要手动导入 ``
 
- 方法:
- Rc::clone(&a)增加引用计数- 
- Rc::clone()增加引用,不会进行数据的深度拷贝操作
- 类型的 .clone()方法一般指定类型数据的深拷贝操作
 
- Rc::strong_count(&a)获得引用计数
- Rc::weak_count()弱引用计数
 
- 使用场景:
- 单线程场景
- 需要在 heap 上分配数据,数据被多个部分读取,编译器无法确认那个部分最后使用
 
#[derive(Debug)]
enum List1 {
    Cons1(i32, Box<List1>),
    Nil1
}
use crate::List1::{Cons1, Nil1};
#[derive(Debug)]
enum List2 {
    Cons2(i32, Rc<List2>),
    Nil2
}
use crate::List2::{Cons2, Nil2};
use std::rc::Rc;
fn main() {
    let a: List1 = Cons1(5,
        Box::new(Cons1(10,
            Box::new(Nil1))));
    let b: List1 = Cons1(1, Box::new(a));
    // let c: List1 = Cons(2,Box::new(a));  // 发生借用
    println!("{:?}", b);
    // Rc<T>
    let a = Rc::new(Cons2(1,
        Rc::new(Cons2(2,
            Rc::new(Nil2)))));
    let b = Cons2(3, Rc::clone(&a));
    let c = Cons2(4, Rc::clone(&a));
    println!("{:?}, {:?}, {:?}, {:?}", a, b, c, Rc::strong_count(&a));
}
内部可变性
- 内部可变模式(interior mutability pattern):不可变类型暴露出可修改其内部值的 API- 
- 它是 Rust 的设计模式之一
- 它允许在支持有不可变引用的前提下对数据进行修改
 
RefCell<T>
- RefCell<T>类型代表了其持有数据的唯一所有权- 
- 只会在运行时检查借用规则,否则引发 panic
- 运行时检查:
- 会延迟暴露问题,可能引发生产事故
- 因借用计数产生性能损失
 
 
- RefCell<T>只适用于单线程场景
- 同一数据的持有者只能由一个
其他
- Ref<T>和- RefMut<T>,通过- RefCell<T>访问:在运行时而不是编译时强制借用规则的类型
- 引用循环(reference cycles):防止内存泄漏发生,Ref<T>和RefCell<T>都可能发生
- 每个项的引用数量无法变为 0,该值不能被释放
- 防止方法:
- 开发者保证
- 通过重组数据结构规避,如将 Rc<T>换成Weak<T>
 
 
- Cell<T>通过复制来访问数据
- Mutex<T>实现跨线程情形的内部可变性模式