Generics
Rust is a systems programming language focused on speed, memory safety, and fearless concurrency — and generics let you write code that works over many types without giving up any of that speed.
Learn Generics in our free Rust course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Rust course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll write generic functions and structs, add trait bounds, and see how Rust compiles them to specialized, zero-cost code.
What You'll Learn in This Lesson
1️⃣ Generic Functions and Trait Bounds
A generic function declares a type parameter in angle brackets, like <T> , then uses T in its signature. When the body needs an operation — comparing values, say — you add a trait bound like T: PartialOrd to require that capability.
One function handled integers, chars, and floats. The bound T: PartialOrd is what makes the > comparison legal — it promises every T can be ordered.
2️⃣ Generic Structs and Methods
Structs can be generic too. Point<T> holds two values of the same type; Pair<T, U> lets the fields differ. Methods go in an impl<T> block, optionally with their own bounds — here T: Display so we can print the fields.
This is exactly how the standard library is built: Vec<T> , Option<T> , and Result<T, E> are all generic types you've already been using.
Your turn. Fill in the blanks marked ___ , then run it.
Write a generic function that swaps the two elements of a same-typed tuple. Run it with cargo run .
📋 Quick Reference — Generics
Practice quiz
What main problem do generics solve?
- Slower runtime
- Memory leaks
- Code duplication across types
- Missing semicolons
Answer: Code duplication across types. Generics let one piece of code work over many types instead of duplicating it.
How do you declare a type parameter on a function?
- fn f<T>(x: T)
- fn f(T x)
Answer: fn f<T>(x: T). A type parameter goes in angle brackets, like fn f<T>(x: T).
What is a trait bound like T: PartialOrd?
- A runtime check
- A default value
- A lifetime
- A requirement that T implements a trait
Answer: A requirement that T implements a trait. It constrains T to types implementing the trait, here enabling comparisons.
Which bound lets you compare values with the > operator?
- T: Display
- T: PartialOrd
- T: Clone
- T: Copy
Answer: T: PartialOrd. PartialOrd provides ordering comparisons like > and <.
Do generics slow your program down at runtime?
- No, they are zero-cost
- Yes, significantly
- Only with floats
- Only in debug builds
Answer: No, they are zero-cost. Monomorphization makes generics zero-cost at runtime.
What is monomorphization?
- Boxing every value
- Garbage collection
- Generating a specialized copy per concrete type at compile time
- Runtime type checking
Answer: Generating a specialized copy per concrete type at compile time. The compiler creates a fully optimized copy for each concrete type used.
How do you write a struct generic over two types?
- struct Pair<T, T>
- struct Pair<T, U>
Answer: struct Pair<T, U>. Two independent parameters are written struct Pair<T, U>.
Where must the type parameter be declared for a generic impl block?
- After the type name
- Inside the method
- It is inferred
- After the impl keyword, as impl<T>
Answer: After the impl keyword, as impl<T>. Write impl<T> Point<T>; the parameter is declared after impl.
Which bound is needed to print a generic value with {}?
- T: PartialOrd
- T: std::fmt::Display
- T: Iterator
- T: Send
Answer: T: std::fmt::Display. Printing with {} requires the Display trait bound.
Which standard-library types are generic?
- Only Vec
- Only String
- Vec<T>, Option<T>, and Result<T, E>
- None of them
Answer: Vec<T>, Option<T>, and Result<T, E>. Vec, Option, and Result are all generic types built the same way.