C.W.K.
Stream
Lesson 05 of 05 · published

A First Taste of Generics

~11 min · types, generics, structs

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

You've written code that only works for one type. Generics let you write it once and have it work for many — without giving up Rust's compile-time type safety.

The problem generics solve

Imagine a Point with two i32 coordinates. Now you need one with f64 coordinates. Copy-pasting the struct with different types is the duplication generics exist to kill. A generic parameter T stands in for 'some type chosen later,' and the compiler stamps out a specialized version for each concrete type you actually use.

Generic structs and methods

struct Point<T> { x: T, y: T } works for any type T. Methods go in impl<T> Point<T>. At each use site, Point<i32> and Point<f64> are distinct, fully type-checked types. There's no runtime cost: generics are monomorphized — the compiler generates concrete code per type, so it runs exactly as fast as if you'd hand-written each version.

Generics are zero-cost. Unlike Java's type erasure or Python's duck typing, Rust monomorphizes: each concrete instantiation becomes its own compiled code. You get the reuse of generics with the speed of hand-specialized types — no boxing, no runtime dispatch.

The limit, and what comes next

A bare T can be stored and moved, but you can't do much with it — you can't add two Ts or print one, because not every type supports those. To say 'T must be addable' or 'T must be printable,' you need trait bounds — and traits are the entire next track. Generics and traits are two halves of one idea; you've just met the first half.

Code

One generic struct, many concrete types·rust
#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn new(x: T, y: T) -> Self {
        Self { x, y }
    }
}

fn main() {
    let ints = Point::new(1, 2);        // Point<i32>
    let floats = Point::new(1.5, 2.5);  // Point<f64> — same struct, different T
    println!("{ints:?} {floats:?}");
}

External links

Exercise

Define Point<T> with a new constructor and create both a Point<i32> and a Point<f64>. Then try to write a method that adds x + y and read the compiler error. Why can't a bare T be added with +?
Hint
Not every type supports +, so the compiler refuses x + y on an unconstrained T. You'd need a trait bound like T: std::ops::Add — exactly what the Traits track teaches next.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue
💛 by Ttoriwarm

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.