In this lesson, you will learn how Rust uses "Marker Traits" and "Auto Traits" like Send and Sync to ensure your concurrent generic code remains memory-safe.
What are Marker Traits?
A Marker Trait is a trait that has no methods or associated types. Its only purpose is to act as a "label" that informs the compiler about a type's properties. Because these traits don't require any logic to be implemented, they are essentially metadata that you attach to your types.
Auto Traits and Concurrency
Send and Sync are special, compiler-provided Auto Traits. You don't usually write impl Send for MyStruct {} manually; instead, the compiler automatically determines if your type implements them based on its fields:
Send: Indicates that ownership of a type can be safely transferred between threads.Sync: Indicates that it is safe for multiple threads to access a type via shared references (&T).
When you write generic code, these traits act as invisible guards. If you create a generic structure that holds a type T, the compiler will check if T is Send before allowing that structure to be sent across a thread boundary.
A Practical Example
Consider a generic worker struct designed to handle tasks in parallel:
struct TaskRunner<T> {
item: T,
}
fn process<T: Send>(runner: TaskRunner<T>) {
// Because of the 'T: Send' bound, the compiler
// guarantees this struct can safely move to another thread.
std::thread::spawn(move || {
// Safe to use 'item' here!
});
}
If you tried to pass a TaskRunner<Rc<i32>> into this function, the compiler would stop you. Why? Because Rc<T> is not Send—it isn't thread-safe for transferring ownership. The T: Send trait bound on the function acts as an automated safety check, preventing race conditions or memory corruption before your code even runs.
By using these marker traits as trait bounds on your generic types, you delegate the burden of concurrency safety to the compiler, ensuring that your abstractions remain robust even as your data structures grow more complex.
Key Takeaway: Marker traits like Send and Sync allow you to define thread-safety requirements for your generic types, letting the compiler verify that your code is safe for concurrent execution.