dyn Trait
علاوه بر استفاده از تریدها برای فراخوانی استاتیک از طریق genericها، Rust همچنین از استفاده از آنها برای فراخوانی داینامیک با تایپهای حذفشده از طریق اشیاء trait پشتیبانی میکند:
struct Dog { name: String, age: i8, } struct Cat { lives: i8, } trait Pet { fn talk(&self) -> String; } impl Pet for Dog { fn talk(&self) -> String { format!(" Woof، نام من {} است!", self.name) } } impl Pet for Cat { fn talk(&self) -> String { String::from("Miau!") } } // Uses generics and static dispatch. fn generic(pet: &impl Pet) { println!("سلام، شما کی هستید؟ {}", pet.talk()); } // Uses type-erasure and dynamic dispatch. fn dynamic(pet: &dyn Pet) { println!("سلام، شما کی هستید؟ {}", pet.talk()); } fn main() { let cat = Cat { lives: 9 }; let dog = Dog { name: String::from("Fido"), age: 5 }; generic(&cat); generic(&dog); dynamic(&cat); dynamic(&dog); }
-
Genericها، از جمله
impl Trait
، از monomorphization برای ایجاد یک نمونه تخصصی از تابع برای هر تایپ مختلفی که با آن نمونهسازی شده استفاده میکنند. این بدان معناست که فراخوانی یک متد trait از درون یک تابع generic همچنان از فراخوانی استاتیک استفاده میکند، زیرا کامپایلر اطلاعات کامل تایپ را دارد و میتواند پیادهسازی trait مربوط به تایپ را مشخص کند. -
زمانی که از
dyn Trait
استفاده میشود، بهجای آن از فراخوانی داینامیک از طریق یک virtual method table (vtable) استفاده میکند. این بدان معناست که یک نسخه واحد ازfn dynamic
وجود دارد که بدون توجه به تایپPet
که وارد میشود، استفاده میشود. -
زمانی که از
dyn Trait
استفاده میشود، شی trait باید پشت یک تایپ واسط قرار داشته باشد. در این مورد، این تایپ واسط یک ارجاع است، اگرچه تایپهای اشارهگرهای هوشمند مانندBox
نیز میتوانند استفاده شوند (این موضوع در روز سوم نشان داده خواهد شد). -
در زمان اجرا، یک
dyn Pet&
بهصورت یک "اشارهگر چاق" (fat pointer) نمایان میشود، یعنی یک جفت از دو اشارهگر: یکی از اشارهگرها به شیء مشخصی کهPet
را پیادهسازی میکند اشاره دارد و دیگری به vtable برای پیادهسازی ترید آن نوع اشاره میکند. هنگام فراخوانی متدtalk
بر رویdyn Pet&
، کامپایلر آدرس تابعtalk
را در vtable جستجو کرده و سپس تابع را فراخوانی میکند و اشارهگر بهDog
یاCat
را به آن تابع پاس میدهد. کامپایلر نیازی به دانستن تایپ مشخصPet
برای انجام این کار ندارد. -
یک
dyn Trait
بهعنوان "تایپ حذف شده" (type-erased) در نظر گرفته میشود، زیرا دیگر در زمان کامپایل اطلاعاتی درباره تایپ مشخص نداریم.