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

Traits နှင့် Trait Bounds

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

  • Traits နှင့် Trait Bounds concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • နမူနာ Rust code ကို ကိုယ်တိုင် run ပြီး output စစ်နိုင်ရန်
  • Tutorial Platform project နှင့် production scenario တွင် မှန်ကန်စွာအသုံးချနိုင်ရန်

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

Trait ဆိုတာ type တစ်ခုက implement လုပ်နိုင်တဲ့ method signature အစုအဝေးတစ်ခုကို define လုပ်ထားတဲ့ concept ဖြစ်ပြီး Java ရဲ့ interface, Go ရဲ့ interface, TypeScript ရဲ့ interface တွေနှင့် ရည်ရွယ်ချက်တူပါတယ်—type အမျိုးမျိုးက behavior တစ်ခုတည်းကို share ပြီး implement လုပ်ချင်ရင် trait ကို သုံးပါတယ်။ Lesson 9 ရဲ့ struct + `impl` block ကို trait နှင့် ချိတ်ဆက်လိုက်ရင် (`impl Summarize for LessonStat { ... }`) type တစ်ခုက trait တစ်ခုရဲ့ contract ကို လိုက်နာကြောင်း compiler ကို ကတိပေးရာရောက်ပါတယ်—trait method တွေကို implement မလုပ်ရင် compile error တက်ပါတယ်။ Trait bound (`fn print_summary<T: Summarize>(item: &T)`) က generic function ကို "ဘယ် operation တွေ actually ခေါ်လို့ရလဲ" ဆိုတဲ့ constraint အနေနဲ့ ကန့်သတ်ပေးတဲ့ Lesson 13 ရဲ့ direct extension ဖြစ်ပါတယ်—`T: Summarize` ဆိုရင် `T` ဟာ `Summarize` trait ရဲ့ method တွေကို implement ထားတဲ့ type ဖြစ်ရမယ်ဆိုတာကို compiler ကို ကတိပေးထားတာပါ။ `impl Trait` syntax (`fn make_lesson() -> impl Summarize`) ကတော့ concrete return type ကို caller ဆီမှာ ဖုံးကွယ်ထားပြီး "ဒီ trait ကို implement လုပ်ထားတဲ့ type တစ်ခုခု ပြန်ပေးမယ်" ဆိုတဲ့ abstraction level ကို ပေးနိုင်ပါတယ်—Java interface return type နှင့် similar ဖြစ်ပေမယ့် Rust မှာ static dispatch (compile time resolve) ဖြစ်တာကြောင့် dynamic dispatch (`dyn Trait`, runtime resolve) ထက် ပိုမြန်ပါတယ်။ Java/C++ interface/abstract class တွေနှင့် Rust trait ရဲ့ အဓိကကွာချက်တစ်ခုက—Rust မှာ trait ကို type တစ်ခု define လုပ်ပြီးတဲ့နောက် (external code ကနေတောင်) implement ထည့်ထားလို့ ရနိုင်ခြင်းဖြစ်ပြီး—inheritance-based design ထက် composition-based design ကို ပိုအားပေးပါတယ်။

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

Content analyzer ရဲ့ `LessonStat`, `Tag` struct နှစ်ခုစလုံးအတွက် common summary behavior ကို share ချင်ရင် `trait Summarize { fn summary(&self) -> String; }` trait ကို define ပြီး `impl Summarize for LessonStat`, `impl Summarize for Tag` နှစ်ခု ရေးမယ်—report generation code ကို `fn print_report<T: Summarize>(item: &T) { println!("{}", item.summary()); }` လို type-agnostic ဖြစ်အောင် ရေးနိုင်ပါတယ်။ Report ထဲမှာ `LessonStat` နှင့် `Tag` items ရော mixed vector တစ်ခုတည်းထဲ ထားချင်ရင်တော့ `Vec<Box<dyn Summarize>>` (dynamic dispatch, Lesson 17 ရဲ့ `Box<T>` ကို ဆက်တွေ့ရမယ်) လိုအပ်လာပါတယ်—static dispatch (`impl Trait`/generic) ကတော့ compile time မှာ type တစ်ခုတည်း သိထားရမယ့် situation အတွက်သာ အကျုံးဝင်ပါတယ်။

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

rust
trait Summarize {
    fn summary(&self) -> String;
}

struct LessonStat { title: String, word_count: u32 }
struct Tag { name: String, uses: u32 }

impl Summarize for LessonStat {
    fn summary(&self) -> String {
        format!("{}: {} words", self.title, self.word_count)
    }
}

impl Summarize for Tag {
    fn summary(&self) -> String {
        format!("#{} ({}x)", self.name, self.uses)
    }
}

fn print_summary<T: Summarize>(item: &T) {
    println!("{}", item.summary());
}

fn main() {
    print_summary(&LessonStat { title: String::from("Traits"), word_count: 700 });
    print_summary(&Tag { name: String::from("rust"), uses: 12 });
}
You should see
"Traits: 700 words" နှင့် "#rust (12x)" ကို function တစ်ခုတည်းကနေ print ထုတ်နိုင်မည်။

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

`trait Describable { fn describe(&self) -> String; }` ဖန်တီးပါ—struct နှစ်ခု (ကိုယ်တိုင်ရွေးချယ်) အတွက် implement လုပ်ပါ—`fn show<T: Describable>(item: &T)` generic function တစ်ခုနှင့် နှစ်ခုလုံးကို ခေါ်ကြည့်ပါ။

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

`trait` ကို define လုပ်ပြီးသားပေမယ့် type တစ်ခုအတွက် `impl Trait for Type` ရေးဖို့ မေ့ခြင်း—trait method ကို ခေါ်ကြိုးစားရင် "method not found" compile error ရနိုင်ပါတယ်—trait ကို define ရုံနှင့် method ရနိုင်တာ မဟုတ်ပါ။

Mixed-type collection (type အမျိုးမျိုး ပါဝင်တဲ့ list) ကို static dispatch generic (`Vec<T>`) ဖြင့် ကိုင်တွယ်ကြိုးစားခြင်း—compile time မှာ type တစ်ခုတည်းသာ သိရမယ်ဆိုတဲ့ generic ရဲ့ limitation ကို လျစ်လျူရှုမိခြင်း—`Vec<Box<dyn Trait>>` လိုအပ်ပါတယ်။

The Rust Programming Language — TraitsRust

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

  • `trait` ကို define လုပ်ပြီးသားပေမယ့် type တစ်ခုအတွက် `impl Trait for Type` ရေးဖို့ မေ့ခြင်း—trait method ကို ခေါ်ကြိုးစားရင် "method not found" compile error ရနိုင်ပါတယ်—trait ကို define ရုံနှင့် method ရနိုင်တာ မဟုတ်ပါ။
  • Mixed-type collection (type အမျိုးမျိုး ပါဝင်တဲ့ list) ကို static dispatch generic (`Vec<T>`) ဖြင့် ကိုင်တွယ်ကြိုးစားခြင်း—compile time မှာ type တစ်ခုတည်းသာ သိရမယ်ဆိုတဲ့ generic ရဲ့ limitation ကို လျစ်လျူရှုမိခြင်း—`Vec<Box<dyn Trait>>` လိုအပ်ပါတယ်။
  • နမူနာ code ကို production system ပေါ် တိုက်ရိုက်မစမ်းဘဲ local/test environment တွင် အရင်အတည်ပြုပါ။

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

`trait Describable { fn describe(&self) -> String; }` ဖန်တီးပါ—struct နှစ်ခု (ကိုယ်တိုင်ရွေးချယ်) အတွက် implement လုပ်ပါ—`fn show<T: Describable>(item: &T)` generic function တစ်ခုနှင့် နှစ်ခုလုံးကို ခေါ်ကြည့်ပါ။

You'll know it worked when: "Traits: 700 words" နှင့် "#rust (12x)" ကို function တစ်ခုတည်းကနေ print ထုတ်နိုင်မည်။

Traits နှင့် Trait Bounds | Thuta Learning