Guide

Generics

Generics let you write code once and use it with many types. A generic type is written as a name in angle brackets, usually T.

Generic functions

Put <T> after the function name. Then T can stand for any type.

fn first<T>(a: T, b: T) -> T {    a}first(1, 2);       // T is i32first("x", "y");   // T is &str

Both a and b are T, so they must be the same type in one call. Without a bound (next unit), you can only move, return or store a T.

Generic structs

A struct can take a type too.

struct Point<T> {    x: T,    y: T,}let a = Point { x: 1, y: 2 };     // Point<i32>let b = Point { x: 1.5, y: 2.0 }; // Point<f64>

x and y share one T, so Point { x: 1, y: 2.0 } fails with E0308. Use two parameters, Point<T, U>, if the fields may differ.

Generic impl blocks

Write impl<T> to add methods for every T.

impl<T> Point<T> {    fn x(&self) -> &T {        &self.x    }}

The first <T> declares the name. The second one, in Point<T>, uses it.

Zero-cost generics

The compiler looks at each type you use with a generic. It writes a separate copy of the code for each one. This is called monomorphization. So first(1, 2) and first("x", "y") use two plain functions: one for i32 and one for &str. There is no extra cost when the program runs. The cost is a bit more compile time and a bigger program.

Remember

  • <T> declares a type parameter; one T means one type.
  • struct Name<T> and impl<T> Name<T> work the same way.
  • Generic code is copied per type at compile time, so it runs as fast as normal code.