0Pricing
Learn Rust Coding · บทเรียน

ออบเจ็กต์คุณลักษณะและ dyn

การเรียกใช้แบบพลวัต

ออบเจ็กต์คุณลักษณะและ dyn เป็นบทเรียน Learn Rust Coding ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Learn Rust Coding และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหา: ชนิดข้อมูลผสมกัน

ชนิดข้อมูลทั่วไปที่มีข้อกำหนดเทรตทำงานได้ดีเมื่อการเรียกใช้แต่ละครั้งใช้ชนิดข้อมูลจริงเพียงชนิดเดียว แต่ถ้าคุณต้องการชุดข้อมูลที่มีชนิดข้อมูลต่างกันซึ่งใช้เทรตร่วมกันล่ะ ชนิดข้อมูลทั่วไปไม่สามารถเก็บข้อมูลหลายชนิดผสมกันได้

อ็อบเจกต์เทรตช่วยแก้ปัญหานี้

อ็อบเจกต์เทรตคืออะไร

อ็อบเจกต์เทรตคือค่าที่อ้างถึงผ่านพอยน์เตอร์ร่วมกับคีย์เวิร์ด dyn เช่น &dyn Trait หรือ Box<dyn Trait>

อ็อบเจกต์นี้ทำให้คุณจัดการชนิดข้อมูลจริงหลายชนิดในลักษณะเดียวกันขณะโปรแกรมทำงาน

Box ของ dyn Trait

Box<dyn Trait> เป็นเจ้าของค่าบนฮีพของชนิดข้อมูลบางชนิดที่นำเทรตไปใช้ คุณเรียกใช้เมธอดของเทรตได้โดยไม่ต้องรู้ชนิดข้อมูลจริง

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn main() {
    let animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.say());
}

เวกเตอร์ของอ็อบเจกต์เทรต

ประโยชน์สำคัญคือ เวกเตอร์หนึ่งตัวสามารถเก็บชนิดข้อมูลต่างกันได้หลายชนิด ตราบใดที่แต่ละชนิดนำเทรตไปใช้

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn main() {
    let zoo: Vec<Box<dyn Speak>> = vec![Box::new(Dog), Box::new(Cat)];
    for animal in &zoo {
        println!("{}", animal.say());
    }
}

การส่งงานแบบไดนามิก

สำหรับออบเจ็กต์ของเทรต เมธอดที่จะเรียกใช้จะถูกเลือก ขณะรันไทม์ โดยค้นหาจากตารางที่ซ่อนอยู่ (ตารางเมธอดเสมือน) ซึ่งเรียกว่า การเรียกใช้แบบไดนามิก

ต้นทุนคือการอ้อมผ่านตัวชี้เล็กน้อย ส่วนประโยชน์คือความยืดหยุ่นขณะรันไทม์

ฟังก์ชันที่คืนค่าออบเจ็กต์ของเทรต

ฟังก์ชันสามารถคืนค่า Box<dyn Trait> ได้เมื่อชนิดรูปธรรมอาจแตกต่างกัน วิธีนี้มีประโยชน์สำหรับฟังก์ชันสร้างออบเจ็กต์ที่ตัดสินใจเลือกชนิดขณะรันไทม์

trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }

fn make(kind: &str) -> Box<dyn Speak> {
    if kind == "dog" { Box::new(Dog) } else { Box::new(Cat) }
}

fn main() {
    println!("{}", make("cat").say());
}

ออบเจ็กต์ของเทรตแบบยืม

คุณยังสามารถส่งออบเจ็กต์ของเทรตแบบยืมด้วย &dyn Trait ได้เมื่อไม่ต้องการความเป็นเจ้าของ วิธีนี้ไม่เกี่ยวข้องกับการจัดสรรหน่วยความจำบนฮีป

trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }

fn announce(s: &dyn Speak) {
    println!("heard: {}", s.say());
}

fn main() {
    let d = Dog;
    announce(&d);
}

ความปลอดภัยของออบเจ็กต์

ไม่ใช่ทุกเทรตที่จะเป็นออบเจ็กต์ของเทรตได้ เทรตต้อง ปลอดภัยสำหรับออบเจ็กต์ กล่าวโดยคร่าว ๆ คือ เมธอดต้องไม่คืนค่า Self ตามค่า หรือใช้พารามิเตอร์ชนิดแบบเจเนอริก

เมธอดที่รับ &self และใช้ชนิดรูปธรรมสามารถใช้ได้

ตัวอย่างที่ไม่ปลอดภัยสำหรับออบเจ็กต์

เทรตที่มีเมธอดซึ่งคืนค่า Self ไม่สามารถใช้เป็น dyn ได้ เพราะไม่ทราบขนาดของ Self ที่อยู่เบื้องหลังตัวชี้ ควรออกแบบเทรตสำหรับออบเจ็กต์ให้เรียบง่าย

ตัวอย่างรูปแบบปลั๊กอิน

ออบเจ็กต์ของเทรตเหมาะอย่างยิ่งกับระบบปลั๊กอิน โดยเก็บรายการตัวจัดการไว้เบื้องหลัง dyn แล้วเรียกใช้ทั้งหมดได้โดยไม่ต้องสนใจชนิดรูปธรรม

trait Task { fn run(&self) -> i32; }
struct Add { a: i32, b: i32 }
struct Negate { x: i32 }
impl Task for Add { fn run(&self) -> i32 { self.a + self.b } }
impl Task for Negate { fn run(&self) -> i32 { -self.x } }

fn main() {
    let tasks: Vec<Box<dyn Task>> = vec![Box::new(Add { a: 2, b: 3 }), Box::new(Negate { x: 7 })];
    let total: i32 = tasks.iter().map(|t| t.run()).sum();
    println!("total {}", total);
}

ควรเลือกใช้ dyn เมื่อใด

ใช้ออบเจ็กต์ของเทรตเมื่อคุณต้องการคอลเลกชันที่มีหลายชนิด ชนิดที่เลือกขณะรันไทม์ หรือต้องการลดการขยายขนาดโค้ดจากการสร้างอินสแตนซ์แบบเจเนอริกจำนวนมาก

ในกรณีอื่น ควรเลือกใช้เจเนอริกเพื่อความเร็วสูงสุด

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจของคุณเกี่ยวกับออบเจ็กต์ของเทรต

สรุปทบทวน

คุณได้เรียนรู้เรื่องการเรียกใช้แบบไดนามิก:

  • ออบเจ็กต์ของเทรตใช้ dyn เบื้องหลังตัวชี้ (Box<dyn T>, &dyn T)
  • ช่วยให้ใช้คอลเลกชันที่มีหลายชนิดและชนิดที่เลือกขณะรันไทม์ได้
  • การเรียกเมธอดจะทำผ่านตารางเมธอดเสมือน (การเรียกใช้แบบไดนามิก)
  • เทรตต้อง ปลอดภัยสำหรับออบเจ็กต์ จึงจะใช้งานในลักษณะนี้ได้

คำถามที่พบบ่อย

บทเรียน “ออบเจ็กต์คุณลักษณะและ dyn” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ออบเจ็กต์คุณลักษณะและ dyn” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Learn Rust Coding ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Learn Rust Coding มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ออบเจ็กต์คุณลักษณะและ dyn”

การเรียกใช้แบบพลวัต คุณปฏิบัติ Learn Rust Coding ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Learn Rust Coding หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Learn Rust Coding บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ออบเจ็กต์คุณลักษณะและ dyn” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Learn Rust Coding นี้ได้ไหม

ได้ บทเรียน Learn Rust Coding ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การกำหนดคุณลักษณะ
  2. ออบเจ็กต์คุณลักษณะและ dyn
  3. การเรียกใช้แบบสแตติกเทียบกับแบบพลวัต
  4. เมธอดเริ่มต้น
← กลับไปที่ Learn Rust Coding