← 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.

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
struct Wrapper<T> {
    value: T,
}

fn main() {
    let int_wrapper = Wrapper { value: 5 };
    let str_wrapper = Wrapper { value: "text" };
    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
struct Pair<A, B> {
    first: A,
    second: B,
}

fn main() {
    let pair = Pair { first: 1, second: "one" };
    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
struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

fn main() {
    let w = Wrapper { value: 42 };
    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
struct Pair<T> {
    a: T,
    b: T,
}

impl<T: PartialOrd + std::fmt::Display> Pair<T> {
    fn larger(&self) -> &T {
        if self.a > self.b { &self.a } else { &self.b }
    }
}

fn main() {
    let pair = Pair { a: 10, b: 20 };
    println!("Larger: {}", pair.larger());
}
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.