**1.**Introduction**2.**Getting Started**3.**Learn Rust**4.**Effective Rust**5.**Syntax and Semantics**5.1.**Variable Bindings**5.2.**Functions**5.3.**Primitive Types**5.4.**Comments**5.5.**if**5.6.**for loops**5.7.**while loops**5.8.**Ownership**5.9.**References and Borrowing**5.10.**Lifetimes**5.11.**Mutability**5.12.**Structs**5.13.**Enums**5.14.**Match**5.15.**Patterns**5.16.**Method Syntax**5.17.**Vectors**5.18.**Strings**5.19.**Generics**5.20.**Traits**5.21.**Drop**5.22.**if let**5.23.**Trait Objects**5.24.**Closures**5.25.**Universal Function Call Syntax**5.26.**Crates and Modules**5.27.**`const` and `static`**5.28.**Attributes**5.29.**`type` aliases**5.30.**Casting between types**5.31.**Associated Types**5.32.**Unsized Types**5.33.**Operators and Overloading**5.34.**Deref coercions**5.35.**Macros**5.36.**Raw Pointers**5.37.**`unsafe`

**6.**Nightly Rust**7.**Glossary**8.**Academic Research

Associated types are a powerful part of Rust’s type system. They’re related to
the idea of a ‘type family’, in other words, grouping multiple types together. That
description is a bit abstract, so let’s dive right into an example. If you want
to write a `Graph`

trait, you have two types to be generic over: the node type
and the edge type. So you might write a trait, `Graph<N, E>`

, that looks like
this:

trait Graph<N, E> { fn has_edge(&self, &N, &N) -> bool; fn edges(&self, &N) -> Vec<E>; // etc }

While this sort of works, it ends up being awkward. For example, any function
that wants to take a `Graph`

as a parameter now *also* needs to be generic over
the `N`

ode and `E`

dge types too:

fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }

Our distance calculation works regardless of our `Edge`

type, so the `E`

stuff in
this signature is just a distraction.

What we really want to say is that a certain `E`

dge and `N`

ode type come together
to form each kind of `Graph`

. We can do that with associated types:

trait Graph { type N; type E; fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec<Self::E>; // etc }

Now, our clients can be abstract over a given `Graph`

:

fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> u32 { ... }

No need to deal with the `E`

dge type here!

Let’s go over all this in more detail.

Let’s build that `Graph`

trait. Here’s the definition:

trait Graph { type N; type E; fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec<Self::E>; }

Simple enough. Associated types use the `type`

keyword, and go inside the body
of the trait, with the functions.

These `type`

declarations can have all the same thing as functions do. For example,
if we wanted our `N`

type to implement `Display`

, so we can print the nodes out,
we could do this:

use std::fmt; trait Graph { type N: fmt::Display; type E; fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec<Self::E>; }

Just like any trait, traits that use associated types use the `impl`

keyword to
provide implementations. Here’s a simple implementation of Graph:

struct Node; struct Edge; struct MyGraph; impl Graph for MyGraph { type N = Node; type E = Edge; fn has_edge(&self, n1: &Node, n2: &Node) -> bool { true } fn edges(&self, n: &Node) -> Vec<Edge> { Vec::new() } }

This silly implementation always returns `true`

and an empty `Vec<Edge>`

, but it
gives you an idea of how to implement this kind of thing. We first need three
`struct`

s, one for the graph, one for the node, and one for the edge. If it made
more sense to use a different type, that would work as well, we’re just going to
use `struct`

s for all three here.

Next is the `impl`

line, which is just like implementing any other trait.

From here, we use `=`

to define our associated types. The name the trait uses
goes on the left of the `=`

, and the concrete type we’re `impl`

ementing this
for goes on the right. Finally, we use the concrete types in our function
declarations.

There’s one more bit of syntax we should talk about: trait objects. If you try to create a trait object from an associated type, like this:

fn main() { trait Graph { type N; type E; fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec<Self::E>; } struct Node; struct Edge; struct MyGraph; impl Graph for MyGraph { type N = Node; type E = Edge; fn has_edge(&self, n1: &Node, n2: &Node) -> bool { true } fn edges(&self, n: &Node) -> Vec<Edge> { Vec::new() } } let graph = MyGraph; let obj = Box::new(graph) as Box<Graph>; }let graph = MyGraph; let obj = Box::new(graph) as Box<Graph>;

You’ll get two errors:

```
error: the value of the associated type `E` (from the trait `main::Graph`) must
be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24:44 error: the value of the associated type `N` (from the trait
`main::Graph`) must be specified [E0191]
let obj = Box::new(graph) as Box<Graph>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

We can’t create a trait object like this, because we don’t know the associated types. Instead, we can write this:

fn main() { trait Graph { type N; type E; fn has_edge(&self, &Self::N, &Self::N) -> bool; fn edges(&self, &Self::N) -> Vec<Self::E>; } struct Node; struct Edge; struct MyGraph; impl Graph for MyGraph { type N = Node; type E = Edge; fn has_edge(&self, n1: &Node, n2: &Node) -> bool { true } fn edges(&self, n: &Node) -> Vec<Edge> { Vec::new() } } let graph = MyGraph; let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>; }let graph = MyGraph; let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;

The `N=Node`

syntax allows us to provide a concrete type, `Node`

, for the `N`

type parameter. Same with `E=Edge`

. If we didn’t provide this constraint, we
couldn’t be sure which `impl`

to match this trait object to.