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

Traits

Trait คือชุดของ method signature — และ method body ที่เป็น optional — ที่อธิบายความสามารถของ type ใดก็ตามที่สัญญาว่าจะจัดหา method เหล่านั้น ถือว่า implement trait นั้น

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

นี่คือการประกาศ method ที่จำเป็นหนึ่งอย่าง struct ใดที่ต้องการเป็น Greet-able จะต้องจัดหา implementation ของ hello ที่เป็น concrete

ใช้ impl TraitName for TypeName เพื่อปฏิบัติตาม trait contract:

struct Dog {
name: String,
}
impl Greet for Dog {
fn hello(&self) -> String {
format!("Woof! I'm {}.", self.name)
}
}

เมื่อ Dog implement Greet แล้ว คุณสามารถเรียก .hello() บน Dog value ใดก็ได้:

let d = Dog { name: String::from("Rex") };
println!("{}", d.hello()); // Woof! I'm Rex.

Trait สามารถจัดหา body เริ่มต้นสำหรับ method ใดก็ได้ ผู้ implement สามารถ override หรือใช้ค่าเริ่มต้นได้:

trait Shape {
fn area(&self) -> f64;
// Default method — implementors get this for free
fn describe(&self) -> String {
format!("I am a shape with area {:.2}", self.area())
}
}

Circle และ Rectangle ต้อง implement แค่ area เท่านั้น Method describe จะถูกรับมาโดยอัตโนมัติและเรียก area ของ type นั้น ณ runtime

Trait method ถูกเรียกด้วย dot syntax ปกติ ตราบเท่าที่ trait อยู่ใน scope หาก trait หลายอันมี method ชื่อเดียวกัน คุณสามารถใช้ fully qualified syntax เพื่อแยกแยะ:

<Circle as Shape>::area(&c)

ในทางปฏิบัติ dot syntax ใช้งานได้ในกรณีส่วนใหญ่

คุณสามารถรับ type ใดก็ตามที่ implement trait โดยใช้ impl TraitName ใน function parameter:

fn print_area(shape: &impl Shape) {
println!("Area: {:.2}", shape.area());
}

นี่คือ shorthand สำหรับ generic function พร้อม trait bound ซึ่งคุณจะเรียนรู้เพิ่มเติมในบทเรียน Generics

Playground ด้านล่างนิยาม trait Shape พร้อม method area ที่ต้อง implement และ method describe แบบ default ทั้ง Circle และ Rectangle implement area และรับ describe มาฟรี

trait Shape {
fn area(&self) -> f64;
fn describe(&self) -> String {
format!("I am a shape with area {:.2}", self.area())
}
}
struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
impl Shape for Rectangle {
fn area(&self) -> f64 {
self.width * self.height
}
}
fn main() {
let c = Circle { radius: 3.0 };
let r = Rectangle { width: 4.0, height: 5.0 };
println!("Circle area: {:.2}", c.area());
println!("{}", c.describe());
println!("Rectangle area: {:.2}", r.area());
println!("{}", r.describe());
}
คุณนิยาม trait ชื่อ `Flyable` พร้อม method `fly` ที่รับ `&self` และไม่คืนค่าอย่างไร?
default method ใน trait คืออะไร?
ใน trait `Shape` ตัวอย่าง method ใดที่มี default implementation?
syntax ใดที่ถูกต้องสำหรับการ implement trait `Shape` ให้กับ struct ชื่อ `Triangle`?