In this article, we explore how traits in Rust allow you to define shared behavior across different types. Think of a trait as a contract: when a type implements a trait, it promises to provide the behaviors defined by that trait. This is similar to interfaces in languages like Java or C#, but with a unique Rust twist.Documentation Index
Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
Use this file to discover all available pages before exploring further.

Why Use Traits?
Traits offer several benefits:- Code Reusability: Define a set of methods once, and then implement them for various types. This reduces redundancy and makes code maintenance easier.
- Polymorphism: Write functions that operate on any type meeting a specific trait requirement, making your code adaptable and extensible.

A Simple Example: The Sendable Trait
Imagine you are building a system that handles different types of messages, such as SMS and emails. Each message type should implement asend method. To achieve this, you can define a trait that enforces this behavior.
Below is an example of the Sendable trait along with two structs (Email and SMS) that implement it:
Sendable trait guarantees that any type that implements it will provide a definition for the send method. Both Email and SMS offer their own specific implementations.
Running the Code
Below is amain function that creates instances of Email and SMS and calls their respective send implementations:
The
Sendable trait acts as a contract ensuring that both Email and SMS provide a send method even though their implementations differ.Using Traits as Function Parameters
Traits enable polymorphism by allowing functions to accept any type that implements a specific trait. For example, consider the following function that accepts an item that implementsSendable:
Email and SMS can be passed to this function:
send_message function doesn’t care if the item is an email or SMS—it only requires that the item implements Sendable.
Default Implementations in Traits
Rust allows you to provide default method implementations within a trait. If a type does not offer its own version, the default is used. For instance, consider an updatedSendable trait with a default send method:
PushNotification, implements Sendable without overriding the send method, the default implementation is applied. Here is the complete example:
Default implementations are useful when a specific behavior is not required for a type, yet the type benefits from implementing the trait.
Using Trait Bounds with Generics
Traits can also be combined with generics to constrain the types that can be passed to a function. The example below creates a function to log any message that implementsSendable:
T: Sendable guarantees that the generic type T implements Sendable. This makes the log_message function both flexible and type-safe.

Summary
Traits in Rust empower developers to define shared behavior with clear contracts, promoting modularity, reusability, and type safety. Here are the key takeaways:- Shared Behavior: Traits define methods that various types can implement, ensuring consistent behavior.
- Polymorphism: Functions can operate on any type that implements the necessary trait.
- Default Implementations: Traits can provide a default behavior that can be overridden by specific types.
- Generics and Trait Bounds: Traits with generics offer flexibility while maintaining type safety.
