ออบเจ็กต์คุณลักษณะและ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การกำหนดคุณลักษณะ
- ออบเจ็กต์คุณลักษณะและ dyn
- การเรียกใช้แบบสแตติกเทียบกับแบบพลวัต
- เมธอดเริ่มต้น