Thuta Learning
ရှာဖွေရန်
Rust
IntermediateProgrammingbeginner

Error Handling — `Result<T, E>` နှင့် `?` Operator

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Error Handling — `Result<T, E>` နှင့် `?` Operator concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • နမူနာ Rust code ကို ကိုယ်တိုင် run ပြီး output စစ်နိုင်ရန်
  • Tutorial Platform project နှင့် production scenario တွင် မှန်ကန်စွာအသုံးချနိုင်ရန်

နားလည်ထားရမယ့် အချက်

Java/Python/JavaScript လို language အများစုမှာ recoverable error (file not found, network timeout) ကို exception throw ပြီး try/catch ဖြင့် handle ပါတယ်—ဒီ approach ရဲ့ ပြဿနာက function signature ကနေ ဒီ function က ဘယ် exception throw နိုင်လဲ ဆိုတာ ကြည့်လို့ မသိနိုင်ဘူးဆိုတာပါ—caller ကို surprise ဖြစ်စေနိုင်ပါတယ်။ Rust ကတော့ Lesson 10 ရဲ့ `Option<T>` ကနေ ဆက်ခံလာတဲ့ pattern—`Result<T, E>` enum (`Ok(T)` success value, `Err(E)` error value)—ကို သုံးပြီး error ကို function signature ရဲ့ return type ထဲမှာပင် explicit ဖော်ပြထားပါတယ်—`fn read_file(path: &str) -> Result<String, io::Error>` ကို ဖတ်တာနဲ့ ဒီ function fail နိုင်ကြောင်း ချက်ချင်းသိနိုင်ပါတယ်။ `?` operator ကတော့ error propagation ကို concise ဖြစ်စေတဲ့ syntax sugar ဖြစ်ပြီး—`let content = read_file(path)?;` က `Ok(value)` ဆိုရင် value ကို unwrap ပြီး `Err(e)` ဆိုရင်တော့ current function ကနေ ချက်ချင်း `Err(e)` ကို early-return ပေးပါတယ်—ဒါက function တစ်ခုစီမှာ nested match statement အများကြီး ရေးရမယ့်အစား error path ကို တစ်ကြောင်းတည်းနဲ့ propagate လုပ်စေပါတယ်။ Rust ရဲ့ philosophy ကတော့ error category နှစ်မျိုးကို ရှင်းရှင်းလင်းလင်း ခွဲထားတာပါ—recoverable error (`Result`) နှင့် unrecoverable error (`panic!`, Lesson 20 မှာ ပိုနက်နက်ရှိုင်းရှိုင်း လေ့လာမယ်)—function တစ်ခုက ဘယ်လို fail နိုင်လဲဆိုတာ type signature ထဲမှာ documentation တစ်ခုအနေနဲ့ ကိုယ်တိုင် ဖော်ပြနေသလိုပါပဲ။

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

Content analyzer ရဲ့ file-reading function ကို `fn read_lesson(path: &str) -> Result<String, io::Error>` လို ရေးမယ်—file မရှိရင် (သို့) permission ပြဿနာရှိရင် caller ဘက်က ဒီ error ကို handle လုပ်ဖို့ compile time မှာ တွန်းအားပေးခံရပါမယ်။ Directory တစ်ခုလုံးကို scan ပြီး file အစီးအရီကို process လုပ်တဲ့ function ထဲမှာ file တစ်ခုချင်းစီကို `read_lesson(path)?` ဖြင့် ခေါ်မယ်—file တစ်ခု fail ရင် whole batch ကို immediately abort လုပ်ပြီး error ကို upstream ဆီ propagate ပေးမယ်။ Report generation function ထဲမှာ `match read_lesson(path) { Ok(content) => ..., Err(e) => eprintln!("skip {path}: {e}") }` ဖြင့် file တစ်ခု fail ရင်တောင် process ကို ဆက်လုပ်ဖို့ decide လို့ရပါတယ်—`?` operator (abort) နှင့် explicit `match` (continue) ကို ဘယ်အခါသုံးမလဲ ဆုံးဖြတ်ရမယ့် real design decision တစ်ခုပါ။

အတူတူ စမ်းရေးကြည့်မယ်

rust
use std::fs;
use std::io;

fn read_lesson(path: &str) -> Result<String, io::Error> {
    let content = fs::read_to_string(path)?;
    Ok(content)
}

fn word_count(path: &str) -> Result<usize, io::Error> {
    let content = read_lesson(path)?;
    Ok(content.split_whitespace().count())
}

fn main() {
    match word_count("lessons/ownership.md") {
        Ok(count) => println!("{count} words"),
        Err(e) => eprintln!("failed to read lesson: {e}"),
    }
}
You should see
File ရှိရင် word count print ထုတ်ပြီး file မရှိရင် error message ကို stderr ဆီ print ထုတ်နိုင်မည်—ဘယ်လိုပဲဖြစ်ဖြစ် program crash ဖြစ်မည်မဟုတ်။

၅ မိနစ် စမ်းကြည့်

`fn parse_difficulty(s: &str) -> Result<u32, String>` ရေးပါ—input string ကို "basic"/"intermediate"/"advanced" နှင့် နှိုင်းယှဉ်ပြီး ကိုက်ညီရင် numeric level (1/2/3) ကို `Ok` ပြန်ပေး၊ မကိုက်ညီရင် descriptive `Err(String)` ပြန်ပေးပါ—`?` operator ကိုသုံးတဲ့ caller function တစ်ခုနှင့်အတူ test ကြည့်ပါ။

သတိလေးတစ်ချက်

`Result` ကို `.unwrap()` ဖြင့် error case ကို handle မလုပ်ဘဲ production code ထဲမှာ သုံးခြင်း—file not found, permission denied စတဲ့ predictable error တွေကတောင် program ကို panic ဖြင့် crash ဖြစ်စေနိုင်ပါတယ်။

`?` operator ကို return type `Result` မဟုတ်တဲ့ function (ဥပမာ `fn main()` plain) ထဲမှာ သုံးကြိုးစားခြင်း—`?` က current function ရဲ့ return type နှင့် error type compatible ဖြစ်မှသာ အလုပ်လုပ်ပါတယ်—compile error ရနိုင်ပါတယ်။

The Rust Programming Language — Recoverable Errors with ResultRust

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • `Result` ကို `.unwrap()` ဖြင့် error case ကို handle မလုပ်ဘဲ production code ထဲမှာ သုံးခြင်း—file not found, permission denied စတဲ့ predictable error တွေကတောင် program ကို panic ဖြင့် crash ဖြစ်စေနိုင်ပါတယ်။
  • `?` operator ကို return type `Result` မဟုတ်တဲ့ function (ဥပမာ `fn main()` plain) ထဲမှာ သုံးကြိုးစားခြင်း—`?` က current function ရဲ့ return type နှင့် error type compatible ဖြစ်မှသာ အလုပ်လုပ်ပါတယ်—compile error ရနိုင်ပါတယ်။
  • နမူနာ code ကို production system ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

လေ့ကျင့်ခန်း

`fn parse_difficulty(s: &str) -> Result<u32, String>` ရေးပါ—input string ကို "basic"/"intermediate"/"advanced" နှင့် နှိုင်းယှဉ်ပြီး ကိုက်ညီရင် numeric level (1/2/3) ကို `Ok` ပြန်ပေး၊ မကိုက်ညီရင် descriptive `Err(String)` ပြန်ပေးပါ—`?` operator ကိုသုံးတဲ့ caller function တစ်ခုနှင့်အတူ test ကြည့်ပါ။

You'll know it worked when: File ရှိရင် word count print ထုတ်ပြီး file မရှိရင် error message ကို stderr ဆီ print ထုတ်နိုင်မည်—ဘယ်လိုပဲဖြစ်ဖြစ် program crash ဖြစ်မည်မဟုတ်။

Error Handling — `Result<T, E>` နှင့် `?` Operator | Thuta Learning