← Back to Rust Course | Chapter 11: Generics & Traits | Lesson 1 of 7

Generic Functions

A generic function is written once but can work with many different types of values, like a universal tool.
Syntax
rust
fn name<T>(param: T) -> T {
    // body
}

name::<Type>(value);

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

markup
fn identity<T>(value: T) -> T {
    value
}

// Entry point: execution of the program starts here
fn main() {
    // Print "{}" to the console, substituting in `identity(5)` (with a trailing newline)
    println!("{}", identity(5));
    // Print "{}" to the console, substituting in `identity("hello")` (with a trailing newline)
    println!("{}", identity("hello"));
}

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

markup
fn largest<T: PartialOrd>(a: T, b: T) -> T {
    // Check whether `a > b { a } else { b }`
    if a > b { a } else { b }
}

// Entry point: execution of the program starts here
fn main() {
    // Print "{}" to the console, substituting in `largest(3, 7)` (with a trailing newline)
    println!("{}", largest(3, 7));
    // Print "{}" to the console, substituting in `largest(2.5, 1.1)` (with a trailing newline)
    println!("{}", largest(2.5, 1.1));
}

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

markup
fn make_pair<A, B>(first: A, second: B) -> (A, B) {
    (first, second)
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `pair`, set to `make_pair(1, "one")`
    let pair = make_pair(1, "one");
    // Print "{:?}" to the console, substituting in `pair` (with a trailing newline)
    println!("{:?}", pair);
}

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

markup
fn double<T: std::ops::Add<Output = T> + Copy>(value: T) -> T {
    value + value
}

// Entry point: execution of the program starts here
fn main() {
    // Print "{}" to the console, substituting in `double(21)` (with a trailing newline)
    println!("{}", double(21));
    // Print "{}" to the console, substituting in `double(1.5)` (with a trailing newline)
    println!("{}", double(1.5));
}
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Forgetting to declare the generic type parameter (<T>) before using it in the function signature.
  2. Assuming a generic function can perform any operation on T -- without trait bounds, only operations valid for every possible type are allowed.
  3. Writing a separate near-identical function for each concrete type instead of factoring out a single generic version.
Chapter Summary
  • 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: PartialOrd restrict T to 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:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.