Skip to content

Rust Generics

You’ve already been using generics without necessarily naming them — Vec<i32> and Option<T> both use them. This page covers writing your own generic functions and structs.

Say you want a function that returns the largest of a list of numbers, for both i32 and f64. Without generics, you’d write it twice:

fn largest_i32(numbers: &[i32]) -> i32 {
let mut largest = numbers[0];
for &n in numbers {
if n > largest {
largest = n;
}
}
largest
}
fn largest_f64(numbers: &[f64]) -> f64 {
let mut largest = numbers[0];
for &n in numbers {
if n > largest {
largest = n;
}
}
largest
}

Same logic, copy-pasted for each type. Generics let you write it once.

fn largest<T: PartialOrd + Copy>(numbers: &[T]) -> T {
let mut largest = numbers[0];
for &n in numbers {
if n > largest {
largest = n;
}
}
largest
}
fn main() {
let integers = [10, 25, 3, 47, 8];
let floats = [1.5, 2.8, 0.3];
println!("{}", largest(&integers));
println!("{}", largest(&floats));
}

Output:

47
2.8
▶ Try it Yourself

<T: PartialOrd + Copy> reads as “for any type T, as long as it can be compared (PartialOrd) and copied (Copy).” T is a placeholder — Rust generates a version of the function for whatever concrete type you actually call it with (i32, f64, and so on).

Structs can be generic too:

struct Pair<T> {
first: T,
second: T,
}
fn main() {
let numbers = Pair { first: 5, second: 10 };
let words = Pair { first: "hello", second: "world" };
println!("{} {}", numbers.first, numbers.second);
println!("{} {}", words.first, words.second);
}

Output:

5 10
hello world
▶ Try it Yourself

One Pair<T> definition works for numbers, text, or any other type — numbers is a Pair<i32> and words is a Pair<&str>, but you only wrote the struct once.

No. Rust generates a separate, specialized version of the function or struct for each concrete type you actually use (this is called monomorphization). By the time your program runs, there’s no generic code left — just ordinary, fully-typed functions, exactly as fast as if you’d hand-written each one.

  • Generics let you write one function or struct that works with multiple types, instead of duplicating code.
  • <T> is a placeholder type; trait bounds (T: PartialOrd) restrict what T is allowed to be.
  • Generic code is compiled into specialized versions per type — no runtime performance cost.