A trait object is a dynamically sized type (DST) that enables late binding (dynamic dispatch) in Rust. It allows a pointer to abstract over different concrete types at runtime, provided those types implement a specific trait. Because the compiler cannot know the size of the underlying concrete type at compile time, trait objects must always be accessed through a pointer, such as a reference (Documentation Index
Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
Use this file to discover all available pages before exploring further.
&dyn Trait) or a smart pointer (Box<dyn Trait>).
Syntax
Thedyn keyword explicitly denotes a trait object, distinguishing dynamic dispatch from static dispatch (which uses impl Trait or generic bounds).
Memory Layout: Fat Pointers
Under the hood, a pointer to a trait object is a fat pointer. It is twice the size of a standard machine pointer (e.g., 16 bytes on a 64-bit architecture) because it consists of two distinct memory addresses:- Data Pointer: A pointer to the actual instance of the concrete type allocated in memory.
- vtable Pointer: A pointer to a Virtual Method Table (vtable) specific to the concrete type.
- Function pointers to the concrete implementations of the trait’s methods.
- The size of the concrete type.
- The memory alignment requirements of the concrete type.
- A pointer to the concrete type’s
dropimplementation.
Dynamic Dispatch Mechanism
When a method is invoked on a trait object, the compiler cannot inline the function call or resolve it directly. Instead, it performs dynamic dispatch:- It dereferences the vtable pointer to locate the vtable for the underlying type.
- It looks up the memory address of the specific method within that vtable.
- It invokes the method, passing the data pointer as the
selfargument.
Object Safety Rules
Not all traits can be coerced into trait objects. A trait must be object-safe to be used with thedyn keyword. The compiler enforces strict rules to ensure a valid vtable can be constructed and that the type can be dynamically sized.
A trait is object-safe if it meets the following criteria:
- The trait must not require
Self: Sized: The trait declaration cannot have aSizedsupertrait bound (e.g.,trait MyTrait: Sized {}). Because a trait object (dyn Trait) is a dynamically sized type, it is inherently!Sizedand cannot implement a trait that mandatesSizedimplementors. - No
Selfin method signatures (except the receiver): Methods cannot use theSelftype anywhere in their signature except as the receiver itself (self,&self,&mut self,Box<Self>, etc.).Selfcannot be used as a return type, nor can it be used as the type of any other parameter (e.g.,fn eq(&self, other: &Self)). IfSelfis used outside the receiver, the compiler cannot guarantee type safety or determine the concrete type’s size at runtime. - No generic type parameters on methods: Methods cannot have generic type parameters. Generics require monomorphization (generating a unique function per type), which would result in an infinitely sized vtable.
- Methods must have a receiver: Methods must take some form of
self. Associated functions without a receiver parameter (often used as constructors) cannot be called on a trait object because there is no instance data to determine which concrete implementation’s vtable to invoke.
where Self: Sized bound to them. This exempts the method from the vtable, allowing the rest of the trait to remain object-safe.
Master Rust with Deep Grasping Methodology!Learn More





