Back to Blog

Rust Generics Tutorial - Write Once, Use With Any Type | Rust for Beginners #24

Sandy LaneSandy Lane

Video: Rust Generics Tutorial - Write Once, Use With Any Type | Rust for Beginners #24 by Taught by Celeste AI - AI Coding Coach

Watch full page →

Rust Generics Tutorial - Write Once, Use With Any Type

Generics in Rust allow you to write flexible and reusable code that works with any data type without duplication. By using generic type parameters, you can create functions and structs that operate on multiple types while maintaining type safety and zero runtime overhead.

Code

use std::fmt::{Debug, Display};

// Generic function that prints any value implementing Debug
fn print_value(value: T) {
  println!("Value: {:?}", value);
}

// Generic struct Point holding any type T
struct Point<T> {
  x: T,
  y: T,
}

// Implementation block for Point with generic type T
impl<T> Point<T> {
  fn new(x: T, y: T) -> Self {
    Point { x, y }
  }
}

// Generic function with trait bounds requiring Display and Debug
fn describe_and_print<T: Display + Debug>(item: T) {
  println!("Description: {}", item);
  println!("Debug info: {:?}", item);
}

// Using where clause for cleaner trait bounds
fn compare_and_print<T>(a: T, b: T)
where
  T: PartialOrd + Display + Debug,
{
  if a > b {
    println!("{} is greater than {}", a, b);
  } else {
    println!("{} is not greater than {}", a, b);
  }
  println!("Debug a: {:?}, Debug b: {:?}", a, b);
}

fn main() {
  print_value(42);               // integer
  print_value("hello");          // string slice
  print_value(3.14);             // float

  let p1 = Point::new(5, 10);   // Point with integers
  let p2 = Point::new(1.1, 4.4); // Point with floats

  describe_and_print("Rust");    // &str implements Display + Debug
  describe_and_print(123);       // i32 implements Display + Debug

  compare_and_print(10, 5);
  compare_and_print(3.5, 7.2);
}

Key Points

  • Generics use angle brackets <T> to define type parameters for functions and structs.
  • Trait bounds (e.g., T: Debug) restrict generics to types that implement specific behavior.
  • Multiple trait bounds can be combined with the plus sign, like T: Display + Debug.
  • The where clause provides a cleaner syntax for complex trait bounds in function signatures.
  • Generics enable writing flexible, type-safe, and zero-cost abstractions in Rust.