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 as 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 a feature called specialization.

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 RFC 2451 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:

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 RFC 255. 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 Sentence case for headingscause 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.