They are used to implement shared/common behavior between types in a abstract manner
Traits are similar to the concept of Interfaces that are present in other languages
Traits are normally declared as public so that other crates can use it when required
A trait does not contain any implementation it only defines the shared behavior
The compiler will enforce that every type that has the trait Summary implements all of its methods
Default Implementation can be provided so that all methods do not have to bee implemented by the type using the trait
The type that implements the trait can always override the default implementation
Traits as Parameters
In the above snippet the function takes item as a parameter and item can be of item of any type that implements the Summary trait
The above two snippets represent the same concept. The 2nd snippet uses the Trait Bound syntax
Depending on the function the impl syntax could be more concise to read
A type that implements multiple type can be denotes using the + operator
When there are multiple generics and trait involved the Trait Bound and impl syntax both can get a little overwhelming to understand
To make the code much more readable we can make use of the where clause
Returning Traits
We can even create functions that return items that implement a trait instead of mentioning an concrete type
This concept in very useful when creating closures and iterators
This syntax has an limitation though it cannot be used to return different types from the function
The above code would result in an error when compiled
By using trait bounds we can implement methods that are only available when the item is of a specific type
In the above snippet, the new() function will be available of Pair of all types but the cmp_display() method will be only available for types that implement the Display and PartialOrd traits
Blanket Implementations
We are implementing the trait ToString on all types of T that implement the trait Display
These implementations are called as Blanket Implementations