Rust เป็นภาษาที่เน้นความปลอดภัยของหน่วยความจำและประสิทธิภาพสูง โดยยังคงความยืดหยุ่นผ่านระบบ Trait, Generics และการทำงานแบบ Polymorphism ซึ่งช่วยให้เราสามารถเขียนโค้ดที่นำกลับมาใช้ซ้ำได้ (Reusable Code) และยัง maintain ได้ง่าย
Trait คืออะไร?
Trait ใน Rust มีลักษณะคล้าย interface ในภาษาอื่น ๆ เช่น Java หรือ TypeScript โดยกำหนดพฤติกรรม (Behavior) ที่ struct ต้อง implement:
trait Speak { fn speak(&self) -> String; } struct Dog; struct Cat; impl Speak for Dog { fn speak(&self) -> String { String::from("Woof!") } } impl Speak for Cat { fn speak(&self) -> String { String::from("Meow!") } }
เราสามารถเขียนฟังก์ชันที่รับ parameter ใด ๆ ก็ตามที่ implement Trait ได้:
fn animal_sound<T: Speak>(animal: T) { println!("{}", animal.speak()); }
Generic คืออะไร?
Generic ช่วยให้เราสามารถเขียนโค้ดที่ทำงานได้กับหลายประเภทข้อมูล โดยไม่ต้องเขียนซ้ำ:
fn print_twice<T: std::fmt::Display>(x: T) { println!("{}", x); println!("{}", x); }
สามารถใช้กับ struct ได้ด้วย:
struct Point<T> { x: T, y: T, } let int_point = Point { x: 1, y: 2 }; let float_point = Point { x: 1.5, y: 2.8 };
Polymorphism แบบ Static และ Dynamic
Polymorphism คือความสามารถในการใช้โค้ดเดียวกันกับ object ที่มีรูปแบบต่างกัน ใน Rust มี 2 รูปแบบ:
- Static Dispatch: ผ่าน generics เช่น
<T: Trait>
ซึ่ง compiler จะเลือก implement ตอน compile-time - Dynamic Dispatch: ผ่าน
dyn Trait
ซึ่งใช้ pointer และ runtime lookup
fn make_speak(animal: &dyn Speak) { println!("{}", animal.speak()); } let dog = Dog; make_speak(&dog);
Trait Bound และ where clause
เมื่อใช้หลาย Trait พร้อมกันสามารถเขียนได้ทั้งแบบ inline และ where
clause:
// แบบ inline fn print_json<T: Serialize + Debug>(item: T) { println!("{:?}", item); } // แบบ where fn print_json2<T>(item: T) where T: Serialize + Debug { println!("{:?}", item); }
Associated Types กับ Traits
สามารถกำหนดชนิดข้อมูลภายใน Trait ได้เช่นกัน:
trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; }
Object Safety และ dyn Trait
หากต้องการใช้ Trait เป็น Trait Object (เช่น Box<dyn Trait>
) Trait นั้นต้องเป็น “object-safe” ซึ่งหมายถึงต้องไม่มี generic method และต้องรับ &self หรือ &mut self เท่านั้น
trait Drawable { fn draw(&self); } fn render(obj: &dyn Drawable) { obj.draw(); }
ภาพประกอบ: Trait vs Generic vs dyn

บทสรุป
- Trait คือ interface ของ Rust
- Generic ทำให้โค้ด reusable ได้
- Polymorphism ช่วยให้โค้ด flexible รองรับหลาย struct ได้
- ใช้ trait bound เพื่อจำกัดความสามารถที่รับได้
- ใช้ dyn Trait เมื่อจำเป็นต้อง dispatch ตอน runtime
บทความโดย poolsawat.com – ชุมชน Rust และภาษาโปรแกรมยุคใหม่