rust所有权规则
Rust的值也可以有多个所有者:
要弄明白这个问题, 我们就需要知道rust的Arc, Rc到底是什么,以及如何使用它们, rust是使用引用计数的智能指针Arc和Rc来实现值的多个所有者的、
首先我们看Rc的基本使用,下面是代码演示:
1 | use std::rc::Rc |
a, b, c是三个创建在栈上面的胖指针, 然后分别指向堆上的数据结构,
上面这种直接在堆上创建数据的机制叫做Box::leak
机制, 可以使rust像C、C++那样在堆上直接创建内存, 然后内存的生命不受到栈上指针的控制, 我们可以通过引用计数, 在适当的时机释放掉这段内存。 关于rc的源码,这里先挖一个坑后面填。
上面我们在堆上创建了一个Rc数据结构, 实现了多个所有权, 但是关于它的可变性,我们还不是清楚, 其实Rc只是一个只读的引用计数器, 我们无法拿到该数据结构内部的可变引用, 来修改这个数据。
所有我们需要一个新的东西, 这个东西叫做RefCell
, 与Rc类似的, 该操作也绕过了静态检查, 允许我们在运行时对某一个只读的数据进行借用, 与此相关的一个特性叫做内部可变性。
既然有内部可变性, 就对应的有外部可变性, 外部可变性是通过let mut
和&mut
来声明实现的, 编译器在编译时就可以知道。
但是有时我们希望不声明mut,但是也想对它进行修改, 这句话的意思是说在编译期间这个值只是只读的(only read), 但是在运行期间这个值可以得到可变借用, 从而修改内部数据。
1 | use std::cell::RefCell; |
上面这个例子, data只是一个RefCell, 其初始值是1, 我们使用borrow_mut()
方法, 来获得一个可变的内部借用, 然后我们使用borrow()
得到一个不可变的内部借用。
我们使用Rc和RefCell解决了多个所有权和运行时可变的特性, 那么在多线程下对同一块内存的访问我们是否依然可以使用Rc解决呢? 答案是不允许的, rc为了性能使用的不是线程安全的引用计数器,因此我们需要使用线程安全的一种计时器, 它的名字叫做Arc, 它实现了线程安全的引用计数器。
相同的, RefCell也不是线程安全的, 如果需要在多线程中,使用内部可变性, rust提供了Mutex和Rwlock, Mutex是互斥量, 获得互斥量的线程对数据独占访问, RwLock是读写锁, 获得写锁的线程对数据实现独占访问, 没写锁, 允许有多个读锁, 可以类比于Rust的借用。
所以多线程下通常使用Arc<Mutex<T>>
和Arc<RwLock<T>>
这两个数据结构