နားလည်ထားရမယ့် အချက်
Lesson 6 ရဲ့ ownership rule ("value တစ်ခုစီ owner တစ်ခုတည်း") ကို strictly လိုက်နာရင် real-world data structure အချို့ (linked list, tree, graph, shared cache) ကို ဖော်ပြဖို့ ခက်ခဲသွားနိုင်ပါတယ်—smart pointer သုံးမျိုးက ဒီ limitation ကို ဖြေရှင်းပေးတဲ့ escape hatch များပါ။ `Box<T>` ဟာ အရိုးရှင်းဆုံးဖြစ်ပြီး value ကို heap ပေါ် allocate လုပ်ပြီး ownership rule ကို ဆက်လိုက်နာသေးပါတယ်—compile time မှာ size မသိရသေးတဲ့ recursive type (ဥပမာ tree node ကို ကိုယ်စားပြုတဲ့ struct ထဲမှာ same type ကို field အနေနဲ့ ထားချင်တဲ့အခါ) အတွက် အသုံးဝင်ပါတယ်—`Box` ရဲ့ fixed pointer size ကနေတစ်ဆင့် compile time size ကို သိစေပါတယ်။ `Rc<T>` (Reference Counted) ကတော့ Lesson 6 ရဲ့ "owner တစ်ခုတည်း" rule ကို relax လုပ်ပေးပါတယ်—value တစ်ခုတည်းကို owner များစွာက share ခွင့်ပြုပြီး internal counter တစ်ခု owner count ကို track လုပ်ကာ counter zero ဖြစ်မှသာ value ကို actually drop လုပ်ပါတယ်—single-threaded context မှာသာ safe ပါတယ်။ `RefCell<T>` ကတော့ borrow checker ရဲ့ compile-time check ကို runtime check ဆီ ရွှေ့ပေးတဲ့ "interior mutability" pattern ဖြစ်ပါတယ်—`&self` (immutable reference) ကို hold ထားပေမယ်တောင် ဒီ value ရဲ့ inner content ကို `.borrow_mut()` ဖြင့် mutate ခွင့်ပြုပေးပြီး Lesson 7 ရဲ့ borrow rule ကို compile time အစား runtime မှာ check ပါတယ်—rule ချိုးဖောက်ရင် compile error အစား runtime panic ဖြစ်နိုင်ပါတယ်။ `Rc<RefCell<T>>` ကို ပေါင်းသုံးရင် single-threaded context တစ်ခုမှာ value တစ်ခုကို owner များစွာက share ပြီး mutate ခွင့်ရနိုင်ပါတယ်—Lesson 18 ရဲ့ multi-threaded equivalent ဖြစ်တဲ့ `Arc<Mutex<T>>` ကို ဆက်တွေ့ရမယ့် pattern ပါ။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Content analyzer ရဲ့ lesson tree structure (chapter ထဲက sub-topic tree) ကို model လုပ်ချင်ရင် `struct TopicNode { name: String, children: Vec<Box<TopicNode>> }` လို `Box` ကို သုံးမယ်—recursive struct ကို compile time size သိအောင် `Box` ကို hop အနေနဲ့ ထည့်ရပါတယ်။ Tag cache တစ်ခုကို analyzer function များစွာက share သုံးချင်ရင် `Rc<Vec<String>>` သုံးမယ်—function တစ်ခုစီက `.clone()` ခေါ်ရင် underlying `Vec` ကို deep copy မဟုတ်ဘဲ reference count ကိုသာ တိုးပေးပါတယ်—memory efficient ဖြစ်ပါတယ်။ Running total counter ကို function များစွာကနေ share update ချင်ရင် `Rc<RefCell<u32>>` သုံးမယ်—`counter.borrow_mut()` ဖြင့် mutate လုပ်ပြီး Lesson 7 ရဲ့ borrow rule ကို runtime check နှင့်အတူ ရနိုင်ပါတယ်။
အတူတူ စမ်းရေးကြည့်မယ်
use std::rc::Rc;
use std::cell::RefCell;
struct TopicNode {
name: String,
children: Vec<Box<TopicNode>>,
}
fn main() {
let leaf = Box::new(TopicNode { name: String::from("Ownership"), children: vec![] });
let root = TopicNode { name: String::from("Basics"), children: vec![leaf] };
println!("{} -> {}", root.name, root.children[0].name);
let counter = Rc::new(RefCell::new(0));
let counter_clone = Rc::clone(&counter);
*counter_clone.borrow_mut() += 5;
println!("shared counter: {}", counter.borrow());
println!("owners: {}", Rc::strong_count(&counter));
}"Basics -> Ownership", "shared counter: 5", "owners: 2" ကို print ထုတ်နိုင်မည်။၅ မိနစ် စမ်းကြည့်
`Rc<RefCell<Vec<String>>>` type ကို သုံးပြီး shared tag list တစ်ခု ဖန်တီးပါ—`.clone()` ဖြင့် owner နှစ်ခု ဖန်တီးပြီး owner တစ်ခုကနေ tag ထည့် (`.borrow_mut().push(...)`) ကာ တခြားတစ်ခု owner ကနေ ပြောင်းလဲမှုကို မြင်ရမလား စစ်ဆေးပါ။
သတိလေးတစ်ချက်
`Rc<T>` ကို multi-threaded context (thread များကြား share) မှာ သုံးကြိုးစားခြင်း—`Rc` ရဲ့ reference counter က thread-safe မဟုတ်ဘဲ compiler က compile error ဖြင့် block ပေးပါလိမ့်မယ်—Lesson 18 ရဲ့ `Arc<T>` (atomic reference count) လိုအပ်ပါတယ်။
`RefCell<T>` ရဲ့ `.borrow_mut()` ကို scope တူတူထဲမှာ borrow active ဖြစ်နေချိန် ထပ်ခေါ်ခြင်း—compile error မဟုတ်ဘဲ "already borrowed" runtime panic ဖြစ်တတ်ပါတယ်—RefCell ရဲ့ safety check က runtime ကျမှသာ ဖြစ်လို့ ဒီ mistake ကို compile time မှာ catch မရနိုင်ပါ။