0Pricing
Learn Rust Coding · Lesson

Generic Structs and Enums

Build flexible data types.

Generic Structs and Enums is a free Learn Rust Coding lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Generic Data Structures

Just like functions, structs and enums can be generic over one or more types. This lets a single definition hold values of any type.

The standard library is built this way: Vec<T>, Option<T>, and Result<T, E> are all generic.

A Generic Struct

Declare the type parameter after the struct name, then use it for fields. Here Point stores two values of the same type T.

One definition now serves integer points, float points, and more.

struct Point<T> {
    x: T,
    y: T,
}

Constructing Generic Structs

When you create an instance, the compiler infers T from the field values. Both fields must agree on the same type.

This program builds an integer point and a float point from the same struct.

struct Point<T> {
    x: T,
    y: T,
}

fn main() {
    let a = Point { x: 1, y: 2 };
    let b = Point { x: 1.5, y: 4.0 };
    println!("{} {}", a.x, b.y);
}

Mixed Type Parameters

Using two parameters lets fields differ. Pair<T, U> can hold an integer and a string at the same time.

Choose one parameter when fields must match, and several when they may vary.

struct Pair<T, U> {
    first: T,
    second: U,
}

Methods on Generic Structs

To add methods, repeat the type parameter on the impl block: impl<T> Point<T>. The parameter after impl declares it; after the type name it applies it.

Here a getter returns a reference to the x field.

struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

Methods With Bounds

You can write methods only for certain concrete types or for types meeting a bound. This impl applies just to Point<f64>.

So dist_from_origin exists on float points but not integer points.

struct Point<T> { x: T, y: T }

impl Point<f64> {
    fn dist_from_origin(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
}

A Generic Enum

Enums are generic too. Each variant can carry generic data. This mirrors the standard Option, which is either Some(T) or None.

Defining your own helps you see how the library type works.

enum Maybe<T> {
    Just(T),
    Nothing,
}

Two Parameters in an Enum

Result uses two parameters so the success and error values can differ. Here is a simplified version.

Multiple type parameters in enums power flexible error handling across the ecosystem.

enum Either<L, R> {
    Left(L),
    Right(R),
}

Matching Generic Enums

You pattern match generic enums exactly like concrete ones. The bound payload becomes a binding inside the arm.

This program unwraps a custom Maybe and prints the contained value or a fallback.

enum Maybe<T> { Just(T), Nothing }

fn main() {
    let m: Maybe<i32> = Maybe::Just(5);
    match m {
        Maybe::Just(n) => println!("got {}", n),
        Maybe::Nothing => println!("empty"),
    }
}

Wrapping a Value

A common pattern is a wrapper struct with one field of type T plus helper methods. Here Wrapper stores and returns any value.

This is the foundation of newtype patterns and smart-pointer-like types.

struct Wrapper<T> { inner: T }

impl<T> Wrapper<T> {
    fn new(v: T) -> Self {
        Wrapper { inner: v }
    }
}

fn main() {
    let w = Wrapper::new("hi");
    println!("{}", w.inner);
}

No Runtime Overhead

Generic structs and enums are also monomorphized. Point<i32> and Point<f64> become two distinct, fully specialized types after compilation.

There is no hidden indirection or tag for the generic type itself.

Quick Check

Test your understanding of generic structs and enums.

Recap

Structs and enums declare type parameters after their name and use them in fields and variants, enabling reusable containers like Option and Result.

Methods repeat parameters on impl<T>, and you can write specialized impl blocks for concrete types. Everything is monomorphized for zero overhead.

Frequently asked questions

Is the “Generic Structs and Enums” lesson free?

Yes — the full text of “Generic Structs and Enums” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.

What will I learn in “Generic Structs and Enums”?

Build flexible data types. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Learn Rust Coding?

No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Generic Structs and Enums” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Learn Rust Coding lesson?

Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Generic Functions
  2. Generic Structs and Enums
  3. Trait Bounds
  4. where Clauses and Multiple Bounds
← Back to Learn Rust Coding