ข้ามไปยังเนื้อหา

Traits และ Generics

สองฟีเจอร์ที่ทรงพลังที่สุดของ Rust ทำงานร่วมกันเพื่อให้คุณเขียน code ที่ทั้ง ยืดหยุ่น และ ปลอดภัย:

  • Traits กำหนด behavior ร่วมกัน — สัญญาที่ type ใดก็ได้สามารถปฏิบัติตามได้
  • Generics เปิดใช้งาน parametric code — function หรือ struct เดียวที่ทำงานกับหลาย type

ทั้งสองอย่างช่วยให้คุณเขียน abstraction ที่ expressive โดยไม่สูญเสียการรับประกัน ณ compile time หรือต้องจ่าย runtime cost

ในหลายภาษา คุณแชร์ behavior ผ่าน inheritance แต่ Rust ใช้แนวทางที่แตกต่าง: คุณนิยาม trait (ชุดของ method signature) และ type ใดก็ได้ก็ implement trait นั้นได้อย่างอิสระ แนวทางนี้คล้ายกับ interface ใน Java หรือ Go แต่มีความสามารถมากกว่า เช่น รองรับ default method body

trait Greet {
fn hello(&self) -> String;
}

struct ใดก็ตามที่ implement Greet ต้องจัดหา method hello trait คือสัญญา และ struct คือผู้ปฏิบัติตามสัญญานั้น

หากไม่มี generics คุณจะต้องสร้าง function แยกกัน เช่น largest_i32, largest_f64 และ largest_char ทั้งที่ body เหมือนกันทุกอย่างแต่ต่างกันแค่ type Generics ให้คุณเขียนครั้งเดียวโดยใช้ type parameter เช่น fn largest<T: PartialOrd>(a: T, b: T) -> T

ส่วน T: PartialOrd คือ trait bound — เป็นตัวบอก compiler ว่า “function นี้ทำงานกับ type T ใดก็ได้ที่รองรับการเปรียบเทียบ” จากนั้น compiler จะสร้าง copy เฉพาะสำหรับแต่ละ concrete type ที่คุณใช้จริง (กระบวนการนี้เรียกว่า monomorphization)

บทเรียนสิ่งที่จะได้เรียนรู้
Traitsนิยาม behavior ร่วมกัน, default methods, การเรียก trait method
GenericsGeneric function, generic struct, trait bound, where clause
Trait Objectsdyn Trait, Box<dyn Trait>, static vs dynamic dispatch
LifetimesLifetime annotation, dangling reference, elision rules

โค้ดด้านล่างแสดง generic function พร้อม trait bound, custom trait และ struct ที่ implement trait นั้น — ทุกแนวคิดที่คุณจะศึกษาอย่างละเอียดในโมดูลนี้

fn main() {
let x: i32 = 42;
println!("x = {}", x);
// Generic function: works for any PartialOrd type
fn largest<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
println!("largest(3, 7) = {}", largest(3, 7));
println!("largest(3.14, 2.71) = {}", largest(3.14, 2.71));
// Trait usage
trait Greet {
fn hello(&self) -> String;
}
struct Person { name: String }
impl Greet for Person {
fn hello(&self) -> String {
format!("Hello, {}!", self.name)
}
}
let p = Person { name: String::from("Rust") };
println!("{}", p.hello());
}
จุดประสงค์หลักของ trait ใน Rust คืออะไร?
Generic type parameter ช่วยให้คุณทำอะไรได้?
ใช้ keyword ใดในการ implement trait ให้กับ struct ใน Rust?