Flexibility in Signatures
Rust has several ways to write code that works with more than one type. Each is a different design commitment:
| Mechanism | Dispatch | Set of types | Reads as |
|---|---|---|---|
enum | match | Closed: you list the variants | “These, and only these.” |
Generics <T: Trait> | Static | Open, fixed at compile time | “Anything with this capability, known now.” |
dyn Trait | Dynamic | Open, chosen at runtime | “Anything with this capability, chosen later.” |
| Composition | None | Not polymorphism | “This is made of parts.” |
A decision procedure, usable in review and in prompts:
- Do you control the full set of variants, and is it small and stable?
Use an enum. As long as matches avoid
_arms, adding a variant produces a compile error everywhere it’s not handled. - Do downstream users need to plug in their own types? Use a trait.
Prefer generics; use
dynfor heterogeneous collections or to keep type parameters out of a public signature. - Is the relationship just “has-a”? Use composition.
In trait definitions
- A generic parameter on the trait (
trait Store<V>) allows one type to implement the trait several times, once perV. - An associated type (
trait Store { type V; }) allows one implementation with one choice ofV. This is usually what you want.