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.
The problem generics solve
Section titled “The problem generics solve”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.
A generic function
Section titled “A generic function”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:
472.8<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).
A generic struct
Section titled “A generic struct”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 10hello worldOne 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.
Does this cost anything at runtime?
Section titled “Does this cost anything at runtime?”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.
Methods on a generic struct
Section titled “Methods on a generic struct”You can add methods to a generic struct with an impl block, just like on the Structs page. The only new part is that the impl needs its own <T> too:
struct Pair<T> { first: T, second: T,}
impl<T> Pair<T> { fn new(first: T, second: T) -> Self { Pair { first, second } }
fn swap(self) -> Pair<T> { Pair { first: self.second, second: self.first } }}
impl Pair<f64> { fn average(&self) -> f64 { (self.first + self.second) / 2.0 }}
fn main() { let words = Pair::new("left", "right").swap(); println!("{} {}", words.first, words.second);
let scores = Pair::new(7.0, 9.0); println!("{}", scores.average());}Output:
right left8There are two kinds of impl block here:
impl<T> Pair<T>means “these methods exist for aPairof any type”. Read the first<T>as “for any typeT”. Without it, Rust would thinkTis the name of a real type and complain that it can’t find it.impl Pair<f64>has no<T>. Its methods exist only forPair<f64>. That’s whyaveragecan use+and/ 2.0. Try callingwords.average()and the compiler will tell you there’s no such method forPair<&str>.
A struct can also have more than one type parameter, like struct Pair<T, U> { first: T, second: U }, when the two fields may have different types. And when the trait bounds get long, you can move them into a where clause to keep the signature readable. That’s covered on the Advanced Traits page.
Practice
Section titled “Practice”1. A generic smallest
Section titled “1. A generic smallest”Write fn smallest<T: PartialOrd + Copy>(items: &[T]) -> T that returns the smallest item. Test it with [8, 3, 5] and with the characters ['r', 'u', 's', 't']. Hint: it’s the largest function from this page with one comparison flipped.
Show solution
fn smallest<T: PartialOrd + Copy>(items: &[T]) -> T { let mut smallest = items[0]; for &item in items { if item < smallest { smallest = item; } } smallest}
fn main() { println!("{}", smallest(&[8, 3, 5])); println!("{}", smallest(&['r', 'u', 's', 't']));}Output:
3r2. The larger half of a Pair
Section titled “2. The larger half of a Pair”Add a method larger(&self) -> &T to Pair<T> that returns a reference to whichever field is bigger. Test it with a Pair of numbers and a Pair of words. Hint: comparing needs PartialOrd, so put the bound on the impl itself: impl<T: PartialOrd> Pair<T>.
Show solution
struct Pair<T> { first: T, second: T,}
impl<T: PartialOrd> Pair<T> { fn larger(&self) -> &T { if self.first > self.second { &self.first } else { &self.second } }}
fn main() { let numbers = Pair { first: 3, second: 9 }; let words = Pair { first: "pear", second: "apple" };
println!("{}", numbers.larger()); println!("{}", words.larger());}Output:
9pear- 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 whatTis allowed to be.impl<T> Pair<T>adds methods for everyT;impl Pair<f64>adds methods for one concrete type only.- Generic code is compiled into specialized versions per type — no runtime performance cost.
Quick check
Section titled “Quick check”Quick check
1. What problem do generics solve?
2. In fn largest<T: PartialOrd + Copy>(...), what does PartialOrd + Copy do?
3. Does using generics cost anything at runtime compared to hand-written code?
4. What does a single struct Pair<T> definition let you do?
Score: 0 / 4
Read more
Section titled “Read more”- Generic Data Types — The Rust Book: generics in functions, structs, enums and methods, including the
largestexample. - Generics — Rust by Example: short runnable examples of generic functions, structs and their syntax.
- Implementation — Rust by Example: more on
impl<T>blocks and implementing methods for one concrete type. - Bounds — Rust by Example: how trait bounds limit what a generic type can be, and why you need them.
- Generic parameters — The Rust Reference: the precise rules, for when you want the full details.