Trait

Traits define functionality that can be shared with several types. Traits are important in generic code. They also allow operator overloading and can provide information about types to the compiler.

Traits are similar to interfaces and type classes in other languages. Since Rust has no class inheritance, traits are the only mechanism for polymorphism.

Example
Here is a trait that allows combining two values of the same type into a new value, also of the same type:

The trait has a required method and a provided method. Required methods don't have a body, so they must be implemented. Provided methods have a default implementation. They can be implemented, which overrides the default one, but they don't need to.

To use the trait, it must first be implemented. Let's do that:

The trait is now implemented for and 2-tuples. The latter implementation is generic: It implements  for any tuple , where   and   are types that implement the   trait.

Let's try it out:

Coherence
Rust requires that trait implementations are coherent. This means that a trait cannot be implemented more than once for any type. For example,  can't be implemented for, because this would overlap with the generic implementation for.

The current plan is to dramatically relax this restriction with .''

Orphan rules
The orphan rules are rules to enforce coherence in projects where some types and traits are used in multiple dependencies. In a way, they simplify dependency management, because they guarantee that implementations in different crates never conflict.

This is a (slightly modified) quote from that explains the orphan rules:

Generally speaking, Rust only permits implementing a trait for a type if either the trait or type were defined in the your crate. However, Rust allows a limited number of implementations that break this rule, if they follow certain rules.

A trait or type is considered local when it is defined in your crate, otherwise it is considered foreign.

When implementing a foreign trait for a foreign type, the trait must have one or more type parameters. A type local to your crate must appear before any use of any type parameters. This means that is valid, but  is not.

The reason that Rust considers order at all is to ensure that your implementation does not conflict with one from another crate. Without this rule, you could write, and another crate could write , which would overlap. For that reason, we require that your local type come before the type parameter, since the only alternative would be disallowing these implementations at all.

Super traits
Traits can inherit from other traits. This is expressed with trait bounds, e.g., which means that  is a super trait of. Every type that implements  must also implement. Trait inheritance should not be confused with class inheritance in object-oriented languages.

In trait bounds, super traits don't need to explicitly specified:

Blanket implementations
Traits can be implemented for several types at once, thanks to generics. For example, it's possible to. However, it's also possible to implement a trait for all types that satisfy a condition, or even all types unconditionally. This is called a blanket implementation:

To ensure coherence, traits with a blanket implementation can only be implemented for other types that can't conflict with the blanket implementation:

Note that inherent s can't be blanket implementations, i.e. is forbidden.

Trait objects
See also: Chapter about trait objects from The Rust Programming Language

Trait objects are objects that implement a specific trait, but their concrete type is unknown. Trait objects enable dynamic dispatch.

Example
Trait object are written as, where  is the trait which the trait object implements. Because their concrete type is unknown, trait objects are dynamically-sized types (DSTs). Values behind a reference or pointer are automatically coerced to trait objects when necessary, which can be observed in the above example in the call.

Because their concrete type is unknown, trait objects implementing the same trait are considered the same type. This enables dynamic dispatch; for example, it's the reason why it's possible to put trait objects of different concrete types in an array.

Trait objects don't carry type information, so they can only access their trait methods. Downcasting a trait object to the concrete type is unsafe. One way to do it safely is to use the trait.

Trait objects with bounds
Trait objects can't have additional bounds, except for lifetimes and auto traits. For example:

This restriction can be bypassed by creating a new trait with several super traits:

Representation of trait objects
Trait objects, like all DSTs, can only exist behind a reference or pointer type, and are fat: They're twice as wide as regular references, because they contain two pointers: One pointer to the data, and one pointer to the virtual method table (vtable).

The vtable is a list of all methods of the trait. It includes the size and alignment of the type and a destructor, which calls the trait if it is implemented.

Object safety
Not all traits can be used as trait objects. One example are traits with a method that returns : Calling such a method on a trait object would return a value with unknown size, which is not allowed. To prevent this, only traits that are object safe can be coerced to a trait object.

Which traits aren't object safe
These rules are defined in. A trait is not object safe, if any of the following conditions are met:

The trait has a bound
The trait  inherits from , requiring the   type to be sized, but trait objects are not sized and don’t implement. Traits default to being possibly-unsized – effectively a bound  – to make more traits object safe by default.

It references
There are two fundamental ways in which this can happen, as an argument or as a return value, in either case a reference to the type means that it must match the type of the  value, the concrete type of which is unknown at compile time. For example:

The types of the two arguments have to match, but this can’t be guaranteed with a trait object, since its concrete type is unknown.

It has static methods
It's not possible to call static methods (functions without a parameter) of a trait object, because then the vtable can't be accessed, so this trait is not object safe:

It has generic methods
Generic functions are monomorphised, that is, a copy of the function is created for each combination of types used as generic parameters. If generic methods in trait objects were allowed, their vtable could become very bloated because of the monomorphised functions. Therefore traits with generic methods are not object safe.

Workarounds
If a trait method violates object safety, it's still possible to make the trait object safe by adding a bound to this method, but then the method is no longer accessible on trait objects:

Note that this might be undesired, as this trait can no longer be implemented for DSTs such as or. An alternative is to split the trait in an object-safe trait an an object-unsafe sub-trait:

Now  is object safe;   can be used when we want to use, and object safety is not required.

Unsafe traits
Unsafe traits are traits that are unsafe to implement; implementing them for certain types can cause undefined behavior. Examples include and.

Auto traits
See also: Reference – Special types and traits

Auto traits are traits that are automatically implemented for many types and have special properties. From the standard library, the, , , and traits are auto traits.

If no explicit implementation or negative implementation is written out for an auto trait for a given type, then the compiler implements it automatically according to the following rules:


 * ,, , , , and implement the trait if   does.
 * Function item types and function pointers automatically implement the trait.
 * Structs, enums, unions, and tuples implement the trait if all of their fields do.
 * Closures implement the trait if the types of all of their captures do. A closure that captures a  by shared reference and a   by value implements any auto traits that both  and   do.

For generic types (counting the built-in types above as generic over ), if a generic implementation is available, then the compiler does not automatically implement it for types that could use the implementation except that they do not meet the requisite trait bounds. For instance, the standard library implements  for all  where   is  ; this means that the compiler will not implement   for  if   is   but not.

Auto traits can also have negative implementations, written as, that override the automatic implementations. For example has a negative implementation of , and so  is not  , even if   is.

Auto traits may be added as an additional bound to any trait object, even though normally only one trait is allowed. For instance, is a valid type.

Auto traits are marker traits, i.e. they cannot have methods or associated items.

Auto traits and negative implementations outside the standard library can only be used with experimental, nightly-only features:

Auto traits were originally called opt-in built-in traits (OIBITs), although they are neither opt-in nor built-in.

Sized trait
The marker trait is automatically implemented for all types that aren't dynamically sized, so their size is known at compile time. It is not an auto trait, but it behaves like one in some ways.

Types that implement

 * Most primitive types implement :
 * Numeric types,  and
 * Function pointers
 * Arrays
 * Pointers, references
 * Never
 * Structs, Enums, Unions and Tuples implement, if all of their fields do.
 * Closures implement  if the types of all of their captures do.
 * Special cases:
 * is  even though   is not. This is different from auto traits (  only implements auto traits that are implemented by  ).
 * does not implement, even though it is zero-sized.

A  trait bound is implicitly added to all generics:

To remove this default trait bound, a relaxed trait bound can be added; this means that the type may or may not be sized. is the only trait where a relaxed trait bound can be used.

Only  types can be used on the stack and passed by value:

Neither  nor   can be manually implemented for a type.

can't be used as a super trait:

The reason is that traits are by default, so more traits can be used as trait objects. If a trait should be restricted to sized traits, a  bound must be added: