The most widespread use of traits is for writing generic functions or types. For
example, the following signature describes a function for consuming any iterator
yielding items of type A
`Ato produce a collection of
A`:
fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
Here, the Iterator
`Iteratortrait specifies an interface that a type
T` must
explicitly implement to be used by this generic function.
Pros:
struct
`structand
` and enum
`enumtype is generic over some type parameter
T, values of type
Twill be laid out _inline_ in the
struct/
`/enum
`enum`, without any indirection.Precise types. Because generics give a name to the specific type implementing a trait, it is possible to be precise about places where that exact type is required or produced. For example, a function
fn main() { fn binary<T: Trait>(x: T, y: T) -> T }fn binary<T: Trait>(x: T, y: T) -> T
is guaranteed to consume and produce elements of exactly the same type T
`T; it cannot be invoked with parameters of different types that both implement
Trait`.
Cons:
T
`Tis a type parameter, it stands for a _single_ actual type. So for example a
VecGeneric types are a form of abstraction, which entails a mental indirection: if
a function takes an argument of type T
`Tbounded by
Trait, clients must first think about the concrete types that implement
Trait` to understand how and when
the function is callable.
To keep the cost of abstraction low, favor widely-known traits. Whenever possible, implement and use traits provided as part of the standard library. Do not introduce new traits for generics lightly; wait until there are a wide range of types that can implement the type.