Generics
Generic functions
Type parameters are declared in angle brackets after the name:
fn identity<T>(x: T) -> T {
x
}
fn const_fn<A, B>(x: A, y: B) -> A {
x
}
fn compose<A, B, C>(f: B -> C, g: A -> B, x: A) -> C {
f(g(x))
}
Generic types
Types take parameters the same way:
type Option<T> = None | Some(T)
type Result<T, E> = Ok(T) | Err(E)
type List<T> = Nil | Cons(T, List<T>)
Inference
Type arguments are inferred from the call site:
let x = identity(42); // T is Nat
let s = identity("hello"); // T is String
Inference also flows from an expected type, which is how a constructor learns its parameters when the value alone does not say:
let none: Option<Nat> = None;
let good: Result<Nat, String> = Ok(42);
None on its own does not determine T — the annotation supplies it. The same
applies to a function’s declared return type, so a constructor in tail position
usually needs no help.
Explicit type arguments are not yet supported. Turbofish syntax —
identity::<Nat>(42)— does not parse. Where inference cannot determine a parameter, annotate the binding or the return type instead, as above. This is the workaround, not a temporary inconvenience with an alternative spelling.
Generic type aliases
Since 1.5
An alias may take parameters, which is useful for naming a recurring instantiation:
pub type ParseResult<T> = Result<(T, Cursor), ParseError>
ParseResult<Nat> then means Result<(Nat, Cursor), ParseError>. This is a
genuine convenience in code that threads one shape through many functions:
fn parse_nat(input: Nat, cur: Cursor) -> ParseResult<Nat> {
Ok((input, cur + 1))
}
An alias introduces no new type — it is the same type under a shorter name, so values flow between the two spellings freely.