Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Rust Dictionary

  1. Home
  2. Rust Dictionary
  3. Generics (<T>) / Type Parameters

Generics (<T>) / Type Parameters

Since: Rust 1.0(2015)

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

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

NotationDescription
<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

sample_generics_basic.rs
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)
}

Compile with the following command:

rustc generics_basic.rs
./generics_basic
7
2.5
(10, 20)
(hello, world)

Common Mistakes

Common mistake 1: using operators without a trait bound

Without a trait bound, operators like >, +, or == cannot be used on a type parameter. Add the appropriate trait bound to unlock the operator.

fn largest<T>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

The same logic can also be written as:

fn largest<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

fn main() {
    println!("{}", largest(3, 7)); // 7
    println!("{}", largest(2.5_f64, 1.8)); // 2.5
}

Common mistake 2: type inference fails without an annotation

When the compiler cannot infer a generic type, a type annotation or the turbofish syntax (::<Type>) is needed.

fn main() {
    // Compile error: type annotations needed for `collect()`
    // let v = (1..=5).collect();

    // Add a type annotation
    let v: Vec<i32> = (1..=5).collect();
    println!("{:?}", v);

    // Or use turbofish syntax
    let v2 = (1..=5).collect::<Vec<i32>>();
    println!("{:?}", v2);
}

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 .