Reference counting

27 ноември 2025

Smart pointers

Reference counting

Reference counting

1 2 3 4 5 6 7 8 9
use std::rc::Rc;

fn main() {
    let first = Rc::new(String::from("foobar"));
    let second = Rc::clone(&first);

    println!("{}", first);
    println!("{}", second);
}
foobar foobar
use std::rc::Rc;

fn main() {
    let first = Rc::new(String::from("foobar"));
    let second = Rc::clone(&first);

    println!("{}", first);
    println!("{}", second);
}

Reference counting

Reference counting

Reference counting

Reference counting

Проблем: стойността е read-only:

1 2 3 4 5
let mut a = Rc::new(3);

*a = 5;

println!("{:?}", a);
error[E0594]: cannot assign to data in an `Rc` --> src/bin/main_daef8d7d55ceabff0dc2ebe0ac97186bb40b3b39.rs:5:1 | 5 | *a = 5; | ^^^^^^ cannot assign | = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc<i32>` For more information about this error, try `rustc --explain E0594`. error: could not compile `rust` (bin "main_daef8d7d55ceabff0dc2ebe0ac97186bb40b3b39") due to 1 previous error
use std::rc::Rc;
fn main() {
let mut a = Rc::new(3);

*a = 5;

println!("{:?}", a);
}

Reference counting

Reference counting

Reference counting

Reference counting

Internal mutability

Internal mutability

RefCell

1 2 3 4 5 6 7 8 9 10
use std::cell::RefCell;

fn main() {
    let cell = RefCell::new(String::from("foo"));   // няма `mut`
    println!("{}", cell.borrow());      // -> std::cell::Ref<String>

    cell.borrow_mut().push_str("bar");  // -> std::cell::RefMut<String>

    println!("{}", cell.borrow());      // -> std::cell::Ref<String>
}
foo foobar
use std::cell::RefCell;

fn main() {
    let cell = RefCell::new(String::from("foo"));   // няма `mut`
    println!("{}", cell.borrow());      // -> std::cell::Ref

    cell.borrow_mut().push_str("bar");  // -> std::cell::RefMut

    println!("{}", cell.borrow());      // -> std::cell::Ref
}

Internal mutability

RefCell

1 2 3 4 5 6 7 8
use std::cell::RefCell;

fn main() {
    let cell = RefCell::new(String::from("foo"));   // отново няма `mut`

    let mut first = cell.borrow_mut();
    let mut second = cell.borrow_mut(); // BOOM!
}
thread 'main' panicked at src/bin/main_45bb39151537827e2a223fcdd3995ba26df346ef.rs:9:27: RefCell already borrowed note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
#![allow(unused_variables)]
#![allow(unused_mut)]
use std::cell::RefCell;

fn main() {
    let cell = RefCell::new(String::from("foo"));   // отново няма `mut`

    let mut first = cell.borrow_mut();
    let mut second = cell.borrow_mut(); // BOOM!
}

Internal mutability

RefCell

Internal mutability

RefCell

Internal mutability

RefCell

Internal mutability

RefCell

Internal mutability

RefCell

Internal mutability

Често RefCell се използва в комбинация с Rc

1 2 3 4 5 6 7 8 9 10 11
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let first = Rc::new(RefCell::new(String::from("foo")));
    let second = Rc::clone(&first);

    first.borrow_mut().push_str("bar");

    println!("{}", second.borrow());
}
foobar
use std::cell::RefCell;
use std::rc::Rc;

fn main() {
    let first = Rc::new(RefCell::new(String::from("foo")));
    let second = Rc::clone(&first);

    first.borrow_mut().push_str("bar");

    println!("{}", second.borrow());
}

Internal mutability

Cell

Още един, по-ограничен тип

Internal mutability

1 2 3 4 5 6 7 8 9 10 11 12 13
use std::cell::Cell;
use std::rc::Rc;

fn main() {
    let first = Rc::new(Cell::new(10));
    let second = Rc::clone(&first);

    println!("{}", second.get());

    first.set(42);

    println!("{}", second.get());
}
10 42
use std::cell::Cell;
use std::rc::Rc;

fn main() {
    let first = Rc::new(Cell::new(10));
    let second = Rc::clone(&first);

    println!("{}", second.get());

    first.set(42);

    println!("{}", second.get());
}

Reference counting

reference cycles

Какво правим, когато структурата ни може да има цикли?

1 2 3 4 5 6 7 8 9 10 11
struct TreeNode {
    value: u32,
    parent: Option<Rc<RefCell<TreeNode>>>,
    children: Vec<Rc<RefCell<TreeNode>>>,
}

impl TreeNode {
    fn new(value: u32, parent: Option<Rc<RefCell<TreeNode>>>) -> Rc<RefCell<TreeNode>> {
        Rc::new(RefCell::new(TreeNode { value, parent, children: vec![] }))
    }
}
#![allow(dead_code)]
use std::rc::Rc;
use std::cell::RefCell;
//norun
struct TreeNode {
    value: u32,
    parent: Option>>,
    children: Vec>>,
}

impl TreeNode {
    fn new(value: u32, parent: Option>>) -> Rc> {
        Rc::new(RefCell::new(TreeNode { value, parent, children: vec![] }))
    }
}
fn main() {}

Reference counting

Side note

Може да си улесните малко живота с type alias:

1 2 3 4 5 6 7 8 9 10 11 12 13
type TreeNodeRef = Rc<RefCell<TreeNode>>;

struct TreeNode {
    value: u32,
    parent: Option<TreeNodeRef>,
    children: Vec<TreeNodeRef>,
}

impl TreeNode {
    fn new(value: u32, parent: Option<TreeNodeRef>) -> TreeNodeRef {
        Rc::new(RefCell::new(TreeNode { value, parent, children: vec![] }))
    }
}
#![allow(dead_code)]
use std::rc::Rc;
use std::cell::RefCell;
//norun

type TreeNodeRef = Rc>;

struct TreeNode {
    value: u32,
    parent: Option,
    children: Vec,
}

impl TreeNode {
    fn new(value: u32, parent: Option) -> TreeNodeRef {
        Rc::new(RefCell::new(TreeNode { value, parent, children: vec![] }))
    }
}
fn main() {}

Reference counting

reference cycles

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
fn make_tree() -> Rc<RefCell<TreeNode>> {
    let root = TreeNode::new(0, None);
    let v1 = TreeNode::new(1, Some(Rc::clone(&root)));
    let v2 = TreeNode::new(2, Some(Rc::clone(&root)));

    {
        let mut r = root.borrow_mut();
        r.children.push(v1);
        r.children.push(v2);
    }

    root
}

fn main() {
    let tree = make_tree();
    println!("{:?}", tree.borrow().value);
    mem::drop(tree);
}
0
#![allow(dead_code)]
use std::rc::Rc;
use std::cell::RefCell;
use std::mem;
#[derive(Debug)]
struct TreeNode {
value: u32,
parent: Option>>,
children: Vec>>,
}
impl TreeNode {
fn new(value: u32, parent: Option>>) -> Rc> {
Rc::new(RefCell::new(TreeNode { value, parent, children: vec![] }))
}
}
fn make_tree() -> Rc> {
    let root = TreeNode::new(0, None);
    let v1 = TreeNode::new(1, Some(Rc::clone(&root)));
    let v2 = TreeNode::new(2, Some(Rc::clone(&root)));

    {
        let mut r = root.borrow_mut();
        r.children.push(v1);
        r.children.push(v2);
    }

    root
}

fn main() {
    let tree = make_tree();
    println!("{:?}", tree.borrow().value);
    mem::drop(tree);
}

Reference counting

reference cycles

Reference counting

reference cycles

Reference counting

reference cycles

Reference counting

Side note

Reference counting

Side note

Reference counting

Side note

Weak reference

Да се върнем на проблема с дървото

Weak reference

Да се върнем на проблема с дървото

Weak reference

Да се върнем на проблема с дървото

Weak reference

Да се върнем на проблема с дървото

Weak reference

1 2 3
downgrade: fn(Rc) -> Weak

upgrade: fn(Weak) -> Option<Rc>

Weak reference

Ето как изглежда в паметта:

Weak reference

1 2 3 4 5 6 7 8 9 10 11 12
use std::mem;
use std::rc::{Rc, Weak};

fn main() {
    let rc = Rc::new(10);
    let weak = Rc::downgrade(&rc);

    println!("{:?}", Weak::upgrade(&weak)); // Option<Rc<T>>

    mem::drop(rc);
    println!("{:?}", Weak::upgrade(&weak)); // Option<Rc<T>>
}
Some(10) None
use std::mem;
use std::rc::{Rc, Weak};

fn main() {
    let rc = Rc::new(10);
    let weak = Rc::downgrade(&rc);

    println!("{:?}", Weak::upgrade(&weak)); // Option>

    mem::drop(rc);
    println!("{:?}", Weak::upgrade(&weak)); // Option>
}

Weak references

Пример

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let gosho_source = "Гошо, Гошо, скочи лошо";
let shared_gosho = Rc::new(gosho_source); // shared_gosho { strong = 1, weak = 0 };

let bratcheda = Rc::clone(&shared_gosho); // shared_gosho { strong = 2, weak = 0 };
// или, shared_gosho.clone(), но първото е по-ясно

let slabichko = Rc::downgrade(&shared_gosho); // shared_gosho { strong = 2, weak = 1 };
println!("{:#?}", Weak::upgrade(&slabichko)); // => Some("Гошо, Гошо, скочи лошо")
                                              // shared_gosho { strong = 3, weak = 1 };
                                              // shared_gosho { strong = 2, weak = 1 };

std::mem::drop(bratcheda); // shared_gosho { strong = 1, weak = 1 };
std::mem::drop(shared_gosho); // shared_gosho { strong = 0, weak = 1 }; => DROP!

println!("{:#?}", Weak::upgrade(&slabichko)); // => None

Weak references

Пример

1 2 3 4 5 6 7 8
// Инициализираме споделената стойност
let gosho_source = "Гошо, Гошо, скочи лошо";
let shared_gosho = Rc::new(gosho_source); // Rc<&str>

let bratcheda = Rc::clone(&shared_gosho); // Rc<&str>

let slabichko = Rc::downgrade(&shared_gosho); // Weak<&str>
println!("{:#?}", Weak::upgrade(&slabichko)); // Option<Rc<&str>>

Въпроси