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

Using Traits as Tags

Implement marker traits to enable specialized method behavior for specific types.

In this lesson, you will learn how to use empty traits as "tags" to signal specific properties of a type to the compiler, allowing you to trigger specialized generic logic.

The Concept of Marker Traits

Sometimes, we want to write a generic function that behaves differently based on a property of the type it receives, such as whether a type is "safe to copy" or "requires encryption." By creating a trait with no methods—often called a marker trait—we can "tag" our types. Because this trait has no implementation requirements, it serves purely as a piece of metadata that the compiler uses to resolve which generic implementation to execute.

Implementing Tagged Specialization

Imagine you have a processing system that handles different data types. You want to ensure that only types marked as Sensitive undergo an encryption step.

struct UserData;
struct PublicLog;

// Define our marker traits
trait Sensitive {}
impl Sensitive for UserData {}

// A generic processor
struct Processor<T> {
    data: T,
}

impl<T> Processor<T> {
    fn process(&self) where T: Sensitive {
        println!("Encrypting sensitive data...");
    }
}

// Without the marker, the method isn't even available
impl<T> Processor<T> {
    fn log(&self) {
        println!("Logging generic data.");
    }
}

In this example, the process method is only visible if the type T implements the Sensitive trait. If you try to call .process() on a Processor<PublicLog>, the code will fail to compile. This is a form of static dispatch that enforces domain rules at compile time rather than relying on runtime checks or if statements.

Why use tags?

  1. Type Safety: You prevent developers from passing the "wrong" kind of data to sensitive functions.
  2. Zero-Cost: Because these traits are empty and used in generic bounds, they are erased at runtime. There is no performance penalty for "tagging" your types.
  3. Intent: It makes your code self-documenting; looking at the impl block immediately tells the next developer which types are permitted for that specific operation.

Key Takeaway: Marker traits act as compile-time flags that allow you to constrain generic behavior without the overhead of runtime checks or manual type inspection.