နားလည်ထားရမယ့် အချက်
Lesson 11 ရဲ့ `Result<T, E>` ကို real project တစ်ခုမှာ သုံးတဲ့အခါ error type `E` ကို ဘယ်လို ဒီဇိုင်းဆွဲမလဲဆိုတာ practical decision တစ်ခုဖြစ်ပါတယ်—function တစ်ခုစီက error source ကွဲပြားစွာ (`io::Error` file read, custom parse error, validation error) ရှိနေရင် ဒီ error type အားလုံးကို represent ပေးနိုင်တဲ့ custom `enum AnalyzerError { Io(io::Error), Parse(String), Validation(String) }` တစ်ခု ဒီဇိုင်းဆွဲသင့်ပါတယ်—ဒါက Lesson 10 ရဲ့ enum concept ကို error handling domain မှာ direct apply လုပ်တာပါ။ `std::error::Error` trait (Lesson 14 ရဲ့ trait concept) ကို ဒီ custom enum အပေါ် implement လုပ်ရင် (`impl std::error::Error for AnalyzerError {}` + `Display` trait) standard error handling ecosystem (logging library, `Box<dyn Error>` return type) နှင့် interoperable ဖြစ်လာပါတယ်—library/application code များစွာမှာ ဒီ pattern ကို standard အဖြစ် မျှော်လင့်ပါတယ်။ `From<io::Error> for AnalyzerError` ကို implement ထားရင် `?` operator ကို function boundary များကြား ဆက်တိုက်သုံးနိုင်ပါတယ်—inner function က `io::Error` ကို return ပေမယ့် outer function ရဲ့ error type က `AnalyzerError` ဆိုရင် `?` က automatic conversion လုပ်ပေးလို့ manual `.map_err(...)` ရေးစရာ မလိုအပ်တော့ပါ—ဒါက Lesson 11 ရဲ့ `?` operator ကို layer များစွာ ရှိတဲ့ real application ထဲမှာ ဘယ်လို scale ဖြစ်လဲ ဖော်ပြတဲ့ direct extension ပါ။ Custom error type ဒီဇိုင်းဆွဲတာဟာ library authoring skill ရဲ့ core တစ်ခုဖြစ်ပြီး—Rust ecosystem ထဲက popular crate (`thiserror`, `anyhow`) တွေက ဒီ boilerplate ကို လျှော့ချပေးတာသာ ဖြစ်ပြီး underlying concept (error type ကို data အဖြစ် explicit ဖော်ပြခြင်း) ကတော့ မပြောင်းလဲပါဘူး။
လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်
Content analyzer module အတွက် `enum AnalyzerError { Io(io::Error), EmptyFile(String) }` ဖန်တီးပြီး `Display` trait ကို implement မယ်—error message ကို human-readable ဖြစ်အောင် format ပေးမယ်။ `impl From<io::Error> for AnalyzerError { fn from(e: io::Error) -> Self { AnalyzerError::Io(e) } }` ကို ရေးမယ်—ဒါကနေ file-reading function (`fs::read_to_string(path)?`) ထဲက `?` operator က automatic conversion ရလာမယ်။ `fn analyze(path: &str) -> Result<u32, AnalyzerError> { let content = fs::read_to_string(path)?; if content.is_empty() { return Err(AnalyzerError::EmptyFile(path.to_string())); } Ok(count_words(&content)) }` ဖြင့် function layer နှစ်ခုကို ဆက်စပ်မယ်—`?` operator တစ်ခုတည်းက error type နှစ်မျိုးလုံးကို seamlessly ကိုင်တွယ်ပေးမှာ ဖြစ်ပါတယ်။
အတူတူ စမ်းရေးကြည့်မယ်
use std::fmt;
use std::fs;
use std::io;
#[derive(Debug)]
enum AnalyzerError {
Io(io::Error),
EmptyFile(String),
}
impl fmt::Display for AnalyzerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AnalyzerError::Io(e) => write!(f, "io error: {e}"),
AnalyzerError::EmptyFile(path) => write!(f, "empty file: {path}"),
}
}
}
impl std::error::Error for AnalyzerError {}
impl From<io::Error> for AnalyzerError {
fn from(e: io::Error) -> Self {
AnalyzerError::Io(e)
}
}
fn analyze(path: &str) -> Result<u32, AnalyzerError> {
let content = fs::read_to_string(path)?;
if content.is_empty() {
return Err(AnalyzerError::EmptyFile(path.to_string()));
}
Ok(content.split_whitespace().count() as u32)
}
fn main() {
match analyze("missing.md") {
Ok(count) => println!("{count} words"),
Err(e) => println!("error: {e}"),
}
}File မရှိရင် "error: io error: ..." ကို print ထုတ်နိုင်မည်—`?` operator က `io::Error` ကို `AnalyzerError` ဆီ automatic convert လုပ်ပေးခဲ့ကြောင်း သက်သေပြမည်။၅ မိနစ် စမ်းကြည့်
`AnalyzerError` ထဲကို `TooManyWords(u32)` variant အသစ် ထပ်ထည့်ပါ—word count ကို 5000 ကျော်ရင် ဒီ error ကို return ပေးအောင် `analyze` function ကို ပြင်ပါ—`Display` implementation ထဲမှာ ဒီ variant အတွက် message ကိုပါ ထည့်ပါ။
သတိလေးတစ်ချက်
Error type ကို `String` တစ်မျိုးတည်း (ဥပမာ `Result<T, String>`) ဖြင့်သာ blanket သုံးခြင်း—caller ဘက်က error kind အလိုက် ကွဲပြားစွာ handle လုပ်ချင်ရင် (ဥပမာ retry logic ကို IO error အတွက်သာ run) string parsing ပြန်လုပ်ရမယ့် fragile design ဖြစ်နိုင်ပါတယ်—custom enum ကသာ ဒီ information ကို ထိန်းသိမ်းပေးပါတယ်။
`From<InnerError> for OuterError` ကို implement မလုပ်ဘဲ `?` operator ကို layer များစွာကြား တိုက်ရိုက်သုံးကြိုးစားခြင်း—error type mismatch compile error ရနိုင်ပါတယ်—`.map_err(AnalyzerError::Io)` ဖြင့် manual convert (သို့) `From` implement လိုအပ်ပါတယ်။