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

Generic Structs

A generic struct is a container you design once, but it can hold whatever kind of value you decide to put in it later.
Syntax
rust
struct Name<T> {
    field: T,
}

impl<T> Name<T> {
    fn method(&self) -> &T {
        &self.field
    }
}

Defining a Generic Struct

A struct can be generic over one or more type parameters, letting the same struct definition hold different concrete types across different instances.

Example: Defining a Generic Struct

markup
// Define a struct `Wrapper` to group related fields together
struct Wrapper<T> {
    value: T,
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `int_wrapper`, set to `Wrapper { value: 5 }`
    let int_wrapper = Wrapper { value: 5 };
    // Declare an immutable variable `str_wrapper`, set to `Wrapper { value: "text" }`
    let str_wrapper = Wrapper { value: "text" };
    // Print "{} and {}" to the console, substituting in `int_wrapper.value, str_wrapper.value` (with a trailing newline)
    println!("{} and {}", int_wrapper.value, str_wrapper.value);
}

Generic Struct with Multiple Type Parameters

A struct can use more than one generic type parameter, allowing its fields to hold independent, potentially different concrete types.

Example: Generic Struct with Multiple Type Parameters

markup
// Define a struct `Pair` to group related fields together
struct Pair<A, B> {
    first: A,
    second: B,
}

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

Methods on a Generic Struct

An impl block for a generic struct repeats the type parameter, letting methods work with the struct's generic field regardless of which concrete type it holds.

Example: Methods on a Generic Struct

markup
// Define a struct `Wrapper` to group related fields together
struct Wrapper<T> {
    value: T,
}

// Implement methods on `Wrapper`
impl<T> Wrapper<T> {
    // Define the function `get` taking `&self` and returning a `&T`
    fn get(&self) -> &T {
        &self.value
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `w`, set to `Wrapper { value: 42 }`
    let w = Wrapper { value: 42 };
    // Print "{}" to the console, substituting in `w.get()` (with a trailing newline)
    println!("{}", w.get());
}

Adding Trait Bounds on Methods

Individual methods can add trait bounds beyond what the struct itself requires, restricting that specific method to types with the needed capability.

Example: Adding Trait Bounds on Methods

markup
// Define a struct `Pair` to group related fields together
struct Pair<T> {
    a: T,
    b: T,
}

// Implement methods on `Pair`
impl<T: PartialOrd + std::fmt::Display> Pair<T> {
    // Define the function `larger` taking `&self` and returning a `&T`
    fn larger(&self) -> &T {
        // Check whether `self.a > self.b { &self.a } else { &self.b }`
        if self.a > self.b { &self.a } else { &self.b }
    }
}

// Entry point: execution of the program starts here
fn main() {
    // Declare an immutable variable `pair`, set to `Pair { a: 10, b: 20 }`
    let pair = Pair { a: 10, b: 20 };
    // Print "Larger: {}" to the console, substituting in `pair.larger()` (with a trailing newline)
    println!("Larger: {}", pair.larger());
}
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 <T> on the struct itself before using T as a field's type.
  2. Assuming a generic struct with one type parameter <T> can hold two different types in two fields typed T -- both fields must match that same concrete type.
  3. Not adding a trait bound when a method inside the impl block needs to perform an operation only some types support.
Chapter Summary
  • A generic struct declares its type parameter in angle brackets, e.g. struct Wrapper<T> { value: T }.
  • All fields typed with the same generic parameter T must hold the same concrete type within one instance.
  • Methods can add extra trait bounds beyond the struct's own declaration when they need specific capabilities.
  • Generic structs let you avoid writing near-duplicate types for each concrete kind of data you want to store.
🔒

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.