# Generics

Generics may be used in:

  • structs
  • functions
  • enums
  • methods

Monomorphization

Generics are not slower than non-generic code. Rust generates concrete types for the generics during compilation. It looks at all the usages of generics in our code and creates types for all the ways that we use them. It's called monomorphization. E.g. Option<i32> becomes Option_i32.

Limitation of generics

An instance of a generic type T with some trait bounds may only be used with one type in place of T. For example, a Vec<T: SomeTrait> is not able to store multiple different types that implement SomeTrait. All of the values it stores need to be of the same type (any type that implements SomeTrait). To have more polymorphic behaviour and be able to store values of different types, Trait Objects should be used.

# Functions

Function example:

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
  let mut largest = list[0];

  for &item in list {
    if item > largest {
      largest = item;
    }
  }
  largest
}

The function largest is generic over some type T.

Traits

The function largest works only with types T that implement the PartialOrd trait (it provides comparing functionality (> operator)) and the Copy trait (to support only the types stored on the stack?).

We can call this function like this:

let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);

# Structs

Struct example:

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 };
}

# Enums

Enum example:

enum Option<T> {
  Some(T),
  None,
}

# Methods

Method example:

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

// the T after impl means that we're defining this method generically
// and T is not any specific type
impl<T> Point<T> {
  fn x(&self) -> &T {
    &self.x
  }
}

We can also specify a method for a concrete type T:

impl Point<f32> {
  fn distance_from_origin(&self) -> f32 {
    (self.x.powi(2) + self.y.powi(2)).sqrt()
  }
}

TIP

In the code above, there is no type after impl, since this method is not generic! Only Point<f32> instances will have this method.

Or, we could specify a method only for Ts that implement some traits:

impl<T: Display + PartialOrd> Point<T> {
  fn cmp_display(&self) {
    if self.x >= self.y {
      println!("The largest member is x = {}", self.x);
    } else P
    println!("The largest member is y = {}", self.y);
  }
}
Last Updated: 1/15/2023, 6:32:34 PM