Rust 内部可变性之Cell和RefCell

内部可变性是指当你有一个不可变引用,但是你可以改变内部值。

Cell和RefCell可以实现内部可变性:
1.Cell包装Copy值,并且没有借用检查;
2.RefCell包装任何类型的值,有运行时借用检查,并且需要用borrow或borrow_mut锁定,分别提供一个不可变或可变引用;
3.Cell和RefCell都不是线程安全的。

Cell和RefCell的区别:

pub struct Cell<T: ?Sized> {
    value: UnsafeCell<T>,
}

pub struct RefCell<T: ?Sized> {
	// 维护了一个T的引用计数
    borrow: Cell<BorrowFlag>,
    // Stores the location of the earliest currently active borrow.
    // This gets updated whenever we go from having zero borrows
    // to having a single borrow. When a borrow occurs, this gets included
    // in the generated `BorrowError/`BorrowMutError`
    #[cfg(feature = "debug_refcell")]
    borrowed_at: Cell<Option<&'static crate::panic::Location<'static>>>,
    value: UnsafeCell<T>,
}

RefCell相比Cell,内部维护了一个包装对象的引用计数。

当通过RefCell的borrow获取一个不可变引用时,内部引用计数加一,当获取的引用离开作用域,内部引用计数减一;

当通过RefCell的borrow_mut获取一个可变引用时,首先检测引用计数是否为0,如果为0,正常返回,如果不为0,直接panic,其实RefCell.borrow时也会做类似的检测,当已经获取了可变引用也是直接panic,当然为了避免panic,我们可以用RefCell.try_borrow和RefCell.try_borrow_mut来获取一个Result类型。

由于Cell并未引入引用计数,所以Cell需要满足T: Copy。

impl<T: Copy> Cell<T> {}

对于Cell而言,通过get获取到的是原有对象的拷贝,set则使用新的对象替换旧的对象。
RefCell没有这个约束,它的操作都是通过返回可变引用完成。

由于实现机制上的差别,Cell只能包装Copy类型,而RefCell能够包装任何类型,所以在一个结构体没有实现Copy的情况下,应该选择使用RefCell。

由于上述差异,RefCell更加常用,通常的做法是配合Rc,组成Rc>

示例代码:
1.Cell

use std::cell::Cell;

#[derive(Debug)]
struct Person {
    name: String,
    age: Cell<usize>,
}

fn main() {
    let person = Person {
        name: "XiaoMing".to_string(),
        age: Cell::new(18),
    };

    let p = &person;
    p.age.set(20);
    // Person { name: "XiaoMing", age: Cell { value: 20 } }
    println!("{:?}", p);
}

2.RefCell

use std::cell::RefCell;

#[derive(Debug)]
struct Person {
    name: String,
    age: RefCell<usize>,
}

fn main() {
    let person = Person {
        name: "XiaoMing".to_string(),
        age: RefCell::new(18),
    };

    let p = &person;
    *p.age.borrow_mut() = 20;
    // Person { name: "XiaoMing", age: Cell { value: 20 } }
    println!("{:?}", p);
}

参考资料
https://www.jianshu.com/p/fa2b5a594305

你可能感兴趣的:(Rust,rust)