နားလည်ထားရမယ့် အချက်
Lesson 7 က borrow checker ရဲ့ core rule (mutable ONE OR immutable MANY) ကို သင်ခဲ့ပေမယ့် ဒီ rule တစ်ခုတည်းနှင့် dangling reference ကို ကာကွယ်ဖို့ မလုံလောက်ပါဘူး—function တစ်ခုက reference ကို parameter နှစ်ခု (သို့) ပိုများကနေ ယူပြီး reference တစ်ခုကို return ပေးမယ်ဆိုရင် ဒီ return ဖြစ်တဲ့ reference က ဘယ် input ကနေ derive လုပ်ထားလဲဆိုတာ compiler က ကိုယ်တိုင် ဆုံးဖြတ်လို့ မရပါဘူး—input တစ်ခု scope ကထွက်သွားရင် output reference က dangling ဖြစ်နိုင်လား ဆိုတာ အသိမပေးနိုင်တော့ပါ။ Lifetime annotation (`fn longest<'a>(x: &'a str, y: &'a str) -> &'a str`) ကတော့ compiler ကို "input reference တွေရဲ့ lifetime (validity duration) က output reference ရဲ့ lifetime နှင့် ဘယ်လို ဆက်စပ်နေလဲ" ဆိုတာကို explicit ဖော်ပြပေးတဲ့ syntax ဖြစ်ပါတယ်—`'a` က actual duration ကို သတ်မှတ်တာ မဟုတ်ဘဲ "ဒီ reference အားလုံးက duration တူတူ valid ဖြစ်ရမယ်" ဆိုတဲ့ constraint ကိုသာ ဖော်ပြတာပါ။ Real code အများစုမှာ compiler က lifetime elision rule (common pattern အလိုက် auto-infer) ကနေ lifetime ကို ကိုယ်တိုင် infer လုပ်ပေးနိုင်လို့ manually ရေးစရာ မလိုအပ်ပါဘူး—annotation ကို explicit ရေးရမှာက ambiguous ဖြစ်တဲ့ (input reference များစွာ ပါဝင်ပြီး output ဘယ်ဟာနှင့်ဆက်စပ်လဲ compiler မဆုံးဖြတ်နိုင်တဲ့) situation တွေမှာသာ ဖြစ်ပါတယ်။ ဒါကို rental agreement တစ်ခုနှင့် တွေးလို့ရပါတယ်—lifetime annotation က "tenant (output reference) ရဲ့ lease က landlord (input reference) ရဲ့ lease duration ထက် မကျော်လွန်နိုင်ဘူး" ဆိုတဲ့ contract term ကို ရေးထားသလိုပါပဲ—duration ကို precisely သတ်မှတ်တာ မဟုတ်ဘဲ relationship ကိုသာ ဖော်ပြတာဖြစ်ပါတယ်။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Content analyzer ရဲ့ `fn longer_tag<'a>(tag1: &'a str, tag2: &'a str) -> &'a str` function ကို ရေးမယ်—tag နှစ်ခုအထဲက length ပိုရှည်တာကို ပြန်ပေးမယ်—`'a` annotation က ဒီ output ဟာ `tag1` (သို့) `tag2` ထဲက တစ်ခုခုက derive လုပ်ထားပြီး နှစ်ခုစလုံးရဲ့ lifetime (valid duration) အထိ output ကို ဆက်သုံးနိုင်တယ်ဆိုတာကို compiler ကို ကတိပေးပါတယ်။ Struct တစ်ခုက reference ကို field အနေနဲ့ hold ချင်ရင် (ဥပမာ `struct LessonExcerpt<'a> { text: &'a str }`) struct instance ဟာ ဒီ `text` field ကနေ ကိုးကားနေတဲ့ original data ထက် ပိုကြာအောင် ရှင်သန်လို့ မရဘူးဆိုတာကို compiler ကို ကတိပေးရပါတယ်—original lesson content string ကို drop လုပ်ပြီးနောက် excerpt ကို ဆက်သုံးကြိုးစားရင် compile error ရနိုင်ပါတယ်။ Lifetime error ကို ရင်ဆိုင်ရင် "data ကို ဘယ်လောက် ကြာကြာ live ထားရမလဲ" ဆိုတဲ့ design question တစ်ခုအနေနဲ့ ဖြေရှင်းသင့်ပါတယ်—reference ဖြစ်ဖြစ်, owned copy (Lesson 6 ရဲ့ `.clone()`) ဖြစ်ဖြစ် tradeoff ကို ပြန်ဆုံးဖြတ်ရမှာပါ။
အတူတူ စမ်းရေးကြည့်မယ်
fn longer_tag<'a>(tag1: &'a str, tag2: &'a str) -> &'a str {
if tag1.len() >= tag2.len() { tag1 } else { tag2 }
}
struct LessonExcerpt<'a> {
text: &'a str,
}
fn main() {
let a = String::from("systems-programming");
let b = String::from("rust");
println!("{}", longer_tag(&a, &b));
let content = String::from("Ownership prevents data races.");
let excerpt = LessonExcerpt { text: &content[..9] };
println!("{}", excerpt.text);
}"systems-programming" နှင့် "Ownership" ကို print ထုတ်နိုင်မည်။၅ မိနစ် စမ်းကြည့်
`fn first_or_second<'a>(a: &'a str, b: &'a str, use_first: bool) -> &'a str` ရေးပါ—`use_first` true ဆိုရင် `a`, false ဆိုရင် `b` ပြန်ပေးရမည်—lifetime annotation ကို ဘာကြောင့်ဒီ function မှာ လိုအပ်သလဲ တစ်ကြောင်းစီ ရှင်းပြပါ။
သတိလေးတစ်ချက်
Struct field ထဲမှာ reference (`&str`) ကို lifetime annotation မထည့်ဘဲ သုံးကြိုးစားခြင်း—compiler က "missing lifetime specifier" error ချက်ချင်းပြပါလိမ့်မယ်—struct ထဲက reference field တိုင်းအတွက် lifetime parameter လိုအပ်ပါတယ်။
Lifetime error ကို ရင်ဆိုင်ရတဲ့အခါ underlying design ပြဿနာကို မကြည့်ဘဲ `'static` (program တစ်ခုလုံး duration) ကို "quick fix" အနေနဲ့ blanket သုံးခြင်း—ဒါက data ရဲ့ real lifetime ကို misrepresent လုပ်ပြီး memory ကို necessary ထက် ပိုကြာအောင် hold ထားစေနိုင်ပါတယ်။
The Rust Programming Language — Validating References with Lifetimes — Rust