[ Rust笔记 十五] 内存安全-内部可变性

Cell

1
2
3
4
5
6
7
8
9
use std::cell::Cell;
fn main() {
let data : Cell<i32> = Cell::new(100);
let p = &data;
data.set(10);
println! ("{}", p.get());
p.set(20);
println! ("{:? }", data);
}

这次编译通过,执行,结果是符合我们的预期的:

10
Cell { value: 20 }

这里虽然变量都没用mut去声明,但是通过set函数改变了内部值。所谓的内部可变性。

cell

cell 的api

1
2
3
4
5
6
7
8
9
10
impl<T> Cell<T> {
pub fn get_mut(&mut self) -> &mut T { }
pub fn set(&self, val: T) { }
pub fn swap(&self, other: &Self) { }
pub fn replace(&self, val: T) -> T { }
pub fn into_inner(self) -> T { }
}
impl<T:Copy> Cell<T> {
pub fn get(&self) -> T { }
}

RefCell

Cell类型没办法制造出直接指向内部数据的指针,而RefCell可以。

1
2
3
4
5
6
7
8
impl<T: ? Sized> RefCell<T> {
pub fn borrow(&self) -> Ref<T> { }
pub fn try_borrow(&self) -> Result<Ref<T>, BorrowError> { }
pub fn borrow_mut(&self) -> RefMut<T> { }
pub fn try_borrow_mut(&self) -> Result<RefMut<T>, BorrowMutError> { }
pub fn get_mut(&mut self) -> &mut T { }
}

use std::cell::RefCell;
fn main() {
    let shared_vec: RefCell<Vec<isize>> = RefCell::new(vec! [1, 2, 3]);
    let shared1 = &shared_vec;
    let shared2 = &shared1;
    shared1.borrow_mut().push(4);
    println! ("{:? }", shared_vec.borrow());
    shared2.borrow_mut().push(5);
    println! ("{:? }", shared_vec.borrow());
}
1
2
3
4
5
6

$ ./test
[1, 2, 3, 4]
[1, 2, 3, 4, 5]


一个panic实例

1
2
3
4
5
6
7
8
9
10
use std::cell::RefCell;
fn main() {
let shared_vec: RefCell<Vec<isize>> = RefCell::new(vec! [1, 2, 3]);
let shared1 = &shared_vec;
let shared2 = &shared1;
let p1 = shared1.borrow();
let p2 = &p1[0];
shared2.borrow_mut().push(4);
println! ("{}", p2);
}

输出

1
2
3
4
$ ./test
thread 'main' panicked at 'already borrowed: BorrowMutError', src\libcore\
result.rs:860:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

RefCell内部有一个“借用计数器”​,调用borrow方法的时候,计数器里面的“共享引用计数”值就加1。当这个borrow结束的时候,会将这个值自动减1​。同样,borrow_mut方法被调用的时候,它就记录一下当前存在“可变引用”​。如果“共享引用”和“可变引用”同时出现了,就会报错。

cell