[Rust] About Cell and RefCell

고승우·2024년 7월 23일
0

Rust

목록 보기
12/16
post-thumbnail

Cell<T>

Cell<T> is a struct that contains a single private value of type T. You can get and set the field even if you don’t have mut access to the Cell itself.

  • Cell::new(value): Creates a new Cell, moving the given value into it.
  • cell.get(): Returns a copy of the value in the cell
  • cell.set(value): Stores the given value in the cell, dropping the previously stored value. It's a safe way of bending the rules on immutability.

RefCell<T>

Like Cell<T>, RefCell<T> is a generic type that contains a single value of type T. Unlike Cell, RefCell borrows references to its T value. As Cell<T>, RefCell<T> uses runtime checks to manage borrowing, borrowing as mutable can invoke panic.

  • RefCell::new(value): Creates a new RefCell, moving value into it.
  • ref_cell.borrow(): Returns a shared reference to the value stored in ref_cell(Ref<T>)
  • ref_cell.borrow_mut(): Returns a mutable reference to the value stored in ref_cell(Ref<T>). This method panics if the value is already borrowed.
  • ref_cell.try_borrow(), ref_cell.try_borrow_mut(): Work just like borrow() and borrow_mut(), but return a Result

Vulnerable point

Rust's compiler strictly enforces lifetimes to prevent errors. However, Cell<T> and RefCell<T> rely on runtime checks, which can lead to issues not caught by the compiler.

    use std::cell::RefCell;
    let ref_cell: RefCell<String> = RefCell::new("hello".to_string());
    let r = ref_cell.borrow(); // ok, returns a Ref<String>
    let count = r.len(); // ok, returns "hello".len()
    assert_eq!(count, 5);
    // drop(r);
    let mut w = ref_cell.borrow_mut(); // panic: already borrowed, but compiler can't detect
    w.push_str(" world");

This code causes a runtime panic because ref_cell is already borrowed. The compiler cannot detect this.

let mut my_string = "hello".to_string();
    let ref_my_string = &my_string;
    let mut_ref_my_string = &mut my_string; // cannot borrow `my_string` as mutable
    println!("{:?}", ref_my_string);

The Rust compiler detects the borrow error at compile time.

Conclusion

While using Cell<T> and RefCell<T>, we need to be cautious as they bypass some of Rust's compile-time safety checks.

profile
٩( ᐛ )و 

0개의 댓글