Day 126 - Generics In Rust

Last time we learned about HashMaps and how we create and insert values into a HashMap etc and now we will be looking at Generics. So What are Generics?

Generics

Geneerics allow us to reduce duplicated code. But that is not all it does. It makes our code more felxible and lets us use whatever type we want for a single function, struct or enums etc. But what does this all mean. Let me explain.

Consider we have a function that adds two numbers. it takes two number as argument and returns a number that is the sum of those two numbers. Both of these numbers we provide are of type i32 and will return type i32 integer.

fn add(x: i32, y: i32) -> i32 {
    x + y
}

But now we want to add two floating point numbers and we cannot do that with out current function because it only accepts integers of type i32 and will return i32. So to do that we can write another function that takes float types and return floating type intergers.

fn add(x: f32, y: f32) {
    x + y
}

First problem with this thing is that we have to add some kind of identification for both function to tell that what function to use at what point. By this i mean that we cannot name both functions the same so we have to name them like f_add and i_add and so.

Second problem with this is that it will create so much duplicate code for all the things that we want to do but to do that we have to rewite the code.

To solution to this and many more problems is called Generics.

Using Generics

Generics are like placeholder types that we use to define a function, enum or struct that we can later reuse with the type of out choice. This means that we only have to write the function add for once and we can use the add function which can return both floats and ints as we want.

To write functions with Generics we use angle brackets after the name of the function and inside those brackets we use a placeholder name and inplace of the return type we use the same plceholder.

fn add<T>(x: T, y: T) -> T {
    x + y
}

Now if we provide the function with i32 it will replace the T with i32 and if we use the f32 it will replace the T with f32 and so on.

add(1, 3); // 4 of type i32
add(1.1, 3.3); // 4.4 of type f32

In Structs

To use Generics in Struct we use the same syntax as in functions.

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

fn main() {
    let ints = Point {x: 10, y: 12};
    let floats = Point {x: 10.5, y: 12.5};
}

Also we can use multiple types in the structs by using more than one types in the angle brackets.

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

fn main() {
    let a = Point {x: 1, y: 1.5};
    let b = Point {x: 1.5, y: 1};
    let c = Point {x: 1, y: 1};
    let d = Point {x: 1.5, y: 1.5};
}

and same goes for enums as well.

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

zainscizainsci