Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rc<T>

Rc<T> (Reference Counted) ให้หลาย owners ได้ ใช้เมื่อต้องการ share ownership

เมื่อไหร่ใช้ Rc?

ปกติ Rust มี owner เดียว แต่บางครั้งต้องการหลาย owners:

      +-----+
      |  a  |
      +--+--+
         |
      +--v--+
      |  5  |<-- want b and c to share this too
      +-----+
         ^
    +----+----+
 +--+--+   +--+--+
 |  b  |   |  c  |
 +-----+   +-----+

การใช้งาน

use std::rc::Rc;

fn main() {
    let a = Rc::new(String::from("hello"));

    println!("Count after a: {}", Rc::strong_count(&a)); // 1

    let b = Rc::clone(&a);  // เพิ่ม reference count
    println!("Count after b: {}", Rc::strong_count(&a)); // 2

    {
        let c = Rc::clone(&a);
        println!("Count in block: {}", Rc::strong_count(&a)); // 3
    } // c dropped, count -= 1

    println!("Count after block: {}", Rc::strong_count(&a)); // 2
}

หมายเหตุ: Rc::clone ไม่ copy data แค่เพิ่ม reference count


Rc::clone vs .clone()

use std::rc::Rc;

fn main() {
    let a = Rc::new(vec![1, 2, 3]);

    // ✅ Preferred: ชัดเจนว่าเพิ่ม reference count
    let b = Rc::clone(&a);

    // ✅ ก็ใช้ได้ แต่อาจสับสนกับ deep clone
    let c = a.clone();

    // Both b and c point to the same data
}

Shared List Example

use std::rc::Rc;

enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use List::{Cons, Nil};

fn main() {
    // a = [5, 10, Nil]
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    println!("Count after a: {}", Rc::strong_count(&a)); // 1

    // b = [3, -> a]
    let b = Cons(3, Rc::clone(&a));
    println!("Count after b: {}", Rc::strong_count(&a)); // 2

    // c = [4, -> a]
    let c = Cons(4, Rc::clone(&a));
    println!("Count after c: {}", Rc::strong_count(&a)); // 3

    // a ถูก share โดย b และ c
}
b: Cons(3, --+
             |     +-------------------------+
             +---->| a: Cons(5, Cons(10, Nil))|
             +---->|                         |
             |     +-------------------------+
c: Cons(4, --+

Rc<T> Properties

PropertyDescription
Single-threadedไม่ thread-safe
Immutableได้แค่ &T ไม่ได้ &mut T
No Copyใช้ Rc::clone()
Automatic dropเมื่อ count เป็น 0

Rc กับ Methods

use std::rc::Rc;

fn main() {
    let a = Rc::new(String::from("hello"));

    // Deref ใช้ methods ของ inner type ได้
    println!("Length: {}", a.len());
    println!("Uppercase: {}", a.to_uppercase());

    // Rc methods
    println!("Strong count: {}", Rc::strong_count(&a));

    // Get reference
    let s: &String = &a;
    println!("Ref: {}", s);
}

Rc::downgrade และ Weak

use std::rc::{Rc, Weak};

fn main() {
    let strong = Rc::new(5);
    let weak: Weak<i32> = Rc::downgrade(&strong);

    println!("Strong count: {}", Rc::strong_count(&strong)); // 1
    println!("Weak count: {}", Rc::weak_count(&strong));     // 1

    // Weak ต้อง upgrade เป็น Rc ก่อนใช้
    if let Some(value) = weak.upgrade() {
        println!("Value: {}", value);
    }

    drop(strong); // strong dropped

    // Weak ยัง upgrade ไม่ได้
    assert!(weak.upgrade().is_none());
}

Weak ใช้ป้องกัน reference cycles (ดูบท 04-weak.md)


ข้อจำกัดของ Rc

use std::rc::Rc;

fn main() {
    let a = Rc::new(5);

    // ❌ Error: cannot borrow as mutable
    // *a += 1;

    // Rc ให้แค่ shared reference (&T)
    // ถ้าต้องการ mutate ใช้ร่วมกับ RefCell
}

Rc + RefCell Pattern

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    // Multiple owners + Interior mutability
    let value = Rc::new(RefCell::new(5));

    let a = Rc::clone(&value);
    let b = Rc::clone(&value);

    // ทั้ง a และ b สามารถ mutate ได้
    *a.borrow_mut() += 10;
    *b.borrow_mut() += 10;

    println!("Value: {}", value.borrow()); // 25
}

ลองทำดู! 🎯

  1. สร้าง shared data ด้วย Rc
  2. Print strong_count ขณะ clone และ drop
  3. ลอง combine Rc กับ RefCell

สรุป

Functionคำอธิบาย
Rc::new(v)สร้าง Rc ใหม่
Rc::clone(&rc)เพิ่ม reference count
Rc::strong_count(&rc)จำนวน strong references
Rc::weak_count(&rc)จำนวน weak references
Rc::downgrade(&rc)สร้าง Weak reference

เมื่อไหร่ใช้

SituationUse
Single ownerปกติ (ไม่ต้อง Rc)
Multiple owners, single-threadRc
Multiple owners, multi-threadArc (บทที่ 15)
Mutability neededRc + RefCell

👉 ต่อไป: RefCell<T>