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
| Property | Description |
|---|---|
| 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
}
ลองทำดู! 🎯
- สร้าง shared data ด้วย Rc
- Print strong_count ขณะ clone และ drop
- ลอง 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 |
เมื่อไหร่ใช้
| Situation | Use |
|---|---|
| Single owner | ปกติ (ไม่ต้อง Rc) |
| Multiple owners, single-thread | Rc |
| Multiple owners, multi-thread | Arc (บทที่ 15) |
| Mutability needed | Rc + RefCell |
👉 ต่อไป: RefCell<T>