Generics (<T>) / Type Parameters
Generics let you define functions, structs, and enums that accept types as parameters. This allows you to reuse the same logic for different types while maintaining type safety.
Syntax
// Generic function
fn function_name<T>(arg: T) -> T { ... }
// Multiple type parameters
fn function_name<T, U>(a: T, b: U) { ... }
// Generic struct
struct StructName<T> {
field: T,
}
// Generic enum (example: definition of Option)
enum Option<T> {
Some(T),
None,
}
// Generic impl block
impl<T> StructName<T> {
fn method_name(&self) -> &T { &self.field }
}
Type Parameter Reference
| Notation | Description |
|---|---|
| <T> | A single type parameter. By convention, a single uppercase letter is used. |
| <T, U> | Multiple type parameters. Each accepts an independent type. |
| <T: Trait> | A type parameter with a trait bound. Restricts the type to those that implement the specified trait. |
| struct Foo<T> | Makes a struct generic. The field type can be specified from outside. |
| impl<T> Foo<T> | Implements methods on a generic struct. |
Sample Code
// Generic function: finds the larger of two values of any comparable type.
fn largest<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
// Generic struct: holds a pair of values of any type.
struct Pair<T> {
first: T,
second: T,
}
impl<T: std::fmt::Display> Pair<T> {
fn show(&self) {
println!("({}, {})", self.first, self.second);
}
}
fn main() {
// The same function works for integers and floats.
println!("{}", largest(3, 7)); // 7
println!("{}", largest(2.5, 1.8)); // 2.5
// The type parameter for the struct is inferred automatically.
let p = Pair { first: 10, second: 20 };
p.show(); // (10, 20)
let s = Pair { first: "hello", second: "world" };
s.show(); // (hello, world)
}
Notes
Generics allow you to reuse the same logic across different types. Rust performs monomorphization at compile time, generating concrete code for each type used, so there is no runtime overhead.
By convention, type parameter names are single uppercase letters such as T, U, and V, but you can use any valid identifier. When multiple type parameters are needed, separate them with commas: <T, U>.
A type parameter without a trait bound cannot use operators such as > or +. If you need to perform specific operations on a type, you must add the appropriate trait bound.
If you find any errors or copyright issues, please contact us.