Generic Functions
In this page:
Defining a Generic Function
A generic type parameter, declared in angle brackets before the parameter list, lets a single function definition work across many different concrete types.
Example: Defining a Generic Function
fn identity<T>(value: T) -> T {
value
}
fn main() {
println!("{}", identity(5));
println!("{}", identity("hello"));
}
Login to try C/C++/Java/PHP code in the editor
Generic Function with a Trait Bound
To perform operations like comparison inside a generic function, you must add a trait bound telling the compiler which types are actually allowed, such as T: PartialOrd.
Example: Generic Function with a Trait Bound
fn largest<T: PartialOrd>(a: T, b: T) -> T {
if a > b { a } else { b }
}
fn main() {
println!("{}", largest(3, 7));
println!("{}", largest(2.5, 1.1));
}
Login to try C/C++/Java/PHP code in the editor
Generics Over Multiple Types
A function can have several independent generic type parameters, each potentially constrained by different trait bounds, letting it flexibly combine unrelated types.
Example: Generics Over Multiple Types
fn make_pair<A, B>(first: A, second: B) -> (A, B) {
(first, second)
}
fn main() {
let pair = make_pair(1, "one");
println!("{:?}", pair);
}
Login to try C/C++/Java/PHP code in the editor
Zero-Cost Abstraction
The Rust compiler generates a specialized version of a generic function for each concrete type it is used with (called monomorphization), so calling a generic function has no runtime overhead compared to writing separate functions by hand.
Example: Zero-Cost Abstraction
fn double<T: std::ops::Add<Output = T> + Copy>(value: T) -> T {
value + value
}
fn main() {
println!("{}", double(21));
println!("{}", double(1.5));
}
Login to try C/C++/Java/PHP code in the editor
- Forgetting to declare the generic type parameter (
<T>) before using it in the function signature. - Assuming a generic function can perform any operation on
T-- without trait bounds, only operations valid for every possible type are allowed. - Writing a separate near-identical function for each concrete type instead of factoring out a single generic version.
- Generic type parameters, written
<T>, let a function operate over many concrete types with one definition. - Without trait bounds, the compiler only allows operations that are valid for absolutely any type.
- Trait bounds like
T: PartialOrdrestrictTto types that support specific operations, such as comparison. - The compiler generates specialized code for each concrete type used, so generics have no runtime performance cost.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: