CodeBlanks Logo Icon CodeBlanks

RefCell<T>

Learn runtime borrowing with RefCell<T>.

RefCell<T>

Borrowing rules are normally checked at compile time. RefCell<T> checks the same rules at runtime, so even data behind an immutable reference can be changed. This is called interior mutability:

use std::cell::RefCell;

let c = RefCell::new(vec![1, 2]);   // c isn't mut!
c.borrow_mut().push(3);
println!("{:?}", c.borrow());       // [1, 2, 3]

The rules are the same (either many readers or one writer); the difference is that a violation is a panic instead of a compile error.

Ref and RefMut

borrow() returns a Ref<T> and borrow_mut() a RefMut<T>. When these go out of scope, the borrow record is cleared. That's why keeping borrows short matters:

let c = RefCell::new(String::from("a"));
c.borrow_mut().push('b');      // temporary RefMut, ends at the end of the line
let uzunluk = c.borrow().len();  // a new read
println!("{uzunluk}");           // 2

Practice Changing an immutable variable

Declare let c = RefCell::new(vec![1, 2]); (without mut). Add 3 with borrow_mut; then print the vector and its length with borrow, separated by a space.

Starter code

main.rs
use std::cell::RefCell;

fn main() {
    // buraya yaz
}

Sample solution

main.rs
use std::cell::RefCell;

fn main() {
    let c = RefCell::new(vec![1, 2]);
    c.borrow_mut().push(3);
    println!("{:?} {}", c.borrow(), c.borrow().len());
}

Expected output

[1, 2, 3] 3

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 When is RefCell preferred?

  • Never
  • For mutations the compiler can't prove but you know are safe Correct answer
  • Always, because it's faster
  • For sharing across threads

Explanation: RefCell has a small runtime cost and is single-threaded; its cross-thread counterpart is Mutex.

2 Mutable borrow

Question
let c = RefCell::new(vec![1, 2]);
c.____().push(3);
Answer
let c = RefCell::new(vec![1, 2]);
c.borrow_mut().push(3);

Explanation: borrow_mut gives a runtime-checked mutable borrow.

3 Method and return

Term Meaning
c.borrow() Ref<T>
c.borrow_mut() RefMut<T>
Two borrow_mut at once Panic
c.into_inner() T (ownership)

All lessons in Intermediate