🚀
9. Generics

Generics

  • Generics are a way to define functions, structs, enums, and methods that work with any type

  • Generics allows us to reduce code duplication

  • Does not affect performance because Rust uses monomorphization to create specific implementations of generic code at compile time

  • T is a generic type parameter

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];
 
    let largest = get_largest(number_list);
 
    println!("The largest number is {}", largest);
}
 
fn get_largest<T>(number_list: Vec<T>) -> T {
    let mut largest = number_list[0];
 
    for &number in number_list.iter() {
        if number > largest {
            largest = number;
        }
    }
 
    largest
}

Error: binary operation > cannot be applied to type T

fn main() {
    let number_list = vec![34, 50, 25, 100, 65];
 
    let largest = get_largest(number_list);
 
    println!("The largest number is {}", largest);
}
 
fn get_largest<T>(number_list: Vec<T>) -> T {
    let mut largest = number_list[0];
 
    for &number in number_list.iter() {
        if number > largest {
            largest = number;
        }
    }
 
    largest
}
fn main() {
    let number_list = vec![34, 50, 25, 100, 65];
 
    let largest = get_largest(number_list);
 
    println!("The largest number is {}", largest);
}
 
fn get_largest<T: PartialOrd + Copy>(number_list: Vec<T>) -> T {
    let mut largest = number_list[0];
 
    for &number in number_list.iter() {
        if number > largest {
            largest = number;
        }
    }
 
    largest
}
  • PartialOrd trait is used to compare values
  • Copy trait is used to copy values
struct Point<T> {
    x: T,
    y: T,
}
fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
 
    println!("integer.x = {}", integer.x);
    println!("float.x = {}", float.x);
}
  • Point struct with generic type T

  • Problem: both x and y must have the same type

struct Point<T, U> {
    x: T,
    y: U,
}
 
fn main() {
    let integer = Point { x: 5, y: 1.0 };
    let float = Point { x: 1.0, y: 4.0 };
 
    println!("integer.x = {}", integer.x);
    println!("float.x = {}", float.x);
}
  • Option & Result enums are generics too
struct Point<T> {
    x: T,
    y: T,
}
 
impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}
 
impl Point<f64> {
    fn y(&self) -> &f64 {
        &self.y
    }
}
 
fn main() {
    let p = Point { x: 5, y: 10 };
 
    p.x();
 
    let p = Point { x: 5.0, y: 10.0 };
    p.y();
 
    println!("p.x = {}", p.x());
}
  • y() method is only available for Point<f64>
struct Point<T, U> {
    x: T,
    y: U,
}
 
impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}
 
fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c' };
 
    let p3 = p1.mixup(p2);
 
    println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
}
  • mixup method is used to mix two Point instances
  • impl<T, U> Point<T, U> is used to define methods for Point struct
  • fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> is a method that takes another Point instance and returns a new Point instance

© 2024 Driptanil Datta.All rights reserved

Made with Love ❤️

Last updated on Mon Oct 20 2025