Course contentsShow
← Rust
Lesson 707 of 1,9106. Generics and Static DispatchFree lesson

Extending Standard Traits for Generics

Build custom wrapper types that delegate generic behavior to internal fields.

In this lesson, you will learn how to build custom wrapper types that delegate behavior to their internal generic fields, allowing you to extend existing traits for your own types.

The Wrapper Pattern

Sometimes you have a generic type, like a struct wrapping a value, and you want it to behave exactly like the type it contains. Instead of reinventing the logic, you can implement a standard trait (like Display, Add, or Iterator) for your wrapper by "delegating" the work to the internal field.

This is a powerful way to add custom functionality or constraints to a type without modifying the original implementation.

Practical Example

Imagine you have a generic Wrapper<T> that you want to be printable. Even if T is generic, you can require that T implements Display so that your wrapper can too.

use std::fmt;

struct Wrapper<T>(T);

// We delegate the implementation to the internal field '0'
impl<T: fmt::Display> fmt::Display for Wrapper<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Delegate the work to T's Display implementation
        write!(f, "Wrapped value: {}", self.0)
    }
}

fn main() {
    let my_val = Wrapper(42);
    println!("{}", my_val);
}

Why Delegate?

By using this pattern, you maintain the "Static Dispatch" benefits we’ve discussed previously. The compiler knows exactly which Display implementation to call because it’s tied to the concrete type T.

When you implement traits this way, you are essentially "extending" the standard trait's capabilities to your custom structure. You can add extra logic—like logging or modifying the output—before or after calling the underlying type's method. This keeps your code modular: the wrapper handles the "envelope" logic, while the internal type handles the "core" logic.

Because you are using generic trait bounds here, your Wrapper only gains these trait implementations when the internal type T meets the necessary criteria, keeping your generic system type-safe and predictable.

Key Takeaway: By implementing standard traits on a wrapper and delegating calls to its generic field, you can easily extend existing behaviors to your own custom data structures while maintaining full type safety.