GENERICS

 GENERICS

  • Generics is a tool which provides effective method for duplicating concepts.
  • Generic enables types to be parameter when defining traits, struct, function etc.
  • struct Point{
      x: i32,
      y : i32
    }
  • In the above example the struct only takes integer value for x and y. Incase you need to pass floating point, you will need to create another struct, but that would  be inefficient.
  • What we can do in this case is:
  • struct Point<T>{
      x: T,
      y : T
    }
  • In the above case we create a genric structure that takes any data type.
  • But this is not a good way as in case we use string to represent point, it will lead to issues like below:
  • struct Point<T>{
      x: T,
      y : T
    }
    
    impl<T> Point<T>{
      fn move_offset(&mut self, x: T, y: T){
        self.x += x;
        self.y += y;
      }
    }
  • The above example will throw an error as the compiler will not know what kind of datatype is T during compile time and incase we use type String it will lead to error as binary operations can't be used on string.
  • use std::ops::AddAssign;
    
    struct Point<T>{
      x: T,
      y : T
    }
    
    impl<T> Point<T>
    where 
        T: AddAssign,
    {
      fn move_offset(&mut self, x: T, y: T){
        self.x += x;
        self.y += y;
      }
    }
  • The above code block shows us how to get rid of the error when using generic types. In the above example we used a trait called AddAssingn (+=).
  • You can sum to point like below:
  • use std::ops::AddAssign;
    #[derive(Debug)]
    struct Point<T>{
      x: T,
      y : T
    }
    
    impl<T: AddAssin> AddAssign for Point<T>{
      fn add_assign(&mut self, other:Self){
        self.x += other.x;
        self.y += other.y;
      }
    }
    
    fn main(){
      point1: Point<f32> = Point{x:32.00, y:54.00};
      point2: Point<f32> = Point{x:323.00, y:32.00};
      point1 +=point2;
      println!9("Sum:{}", point1);
    }

PARTIAL EQ

  • It enables us to compare two instances of a struct like below:
  • #[derive(Debug)]
    struct Point<T>{
      x: T,
      y : T
    }
    
    impl<T: PartialEq> PartialEq for Point<T>{
      fn eq(&self, other:&Self){
        self.x += other.x && self.y += other.y;
      }
    }
    
    fn main(){
      point1: Point<f32> = Point{x:32.00, y:54.00};
      point2: Point<f32> = Point{x:323.00, y:32.00};
      if point1 == point2{
        println!("They are both equal);
      }
    }
  • #[derive(Debug)]
    trait CanRun{
       fn run(&self);
    }
    
    trait CanWalk{
       fn walk(&self);
    }
    
    impl <T:CanRun> CanRun for Vec<T>{
      fn run(&self){
        for item: &T in self{
           item.run();
        }
      }
    }
    impl <T:CanWalk> CanWalk for Vec<T>{
      fn walk(&self){
        for item: &T in self{
           item.walk();
        }
      }
    }
    
    struct Person{
      name:String
    }
    
    struct Elephant{
      name:String
    }
    
    impl CanWalk for Elephant{
      fn walk(&self){
        println!("{} is running", self.name);
      }
    }
    
    impl CanWalk for Person{
      fn walk(&self){
        println!("{} is running", self.name);
      }
    }
    impl CanRun for Person{
      fn walk(&self){
        println!("{} is running", self.name);
      }
    }
    
    fn main(){
       let people: Vec<Person> = vec![
          Person {
            name: "John.to_string(),
          },
          Person {
            name: "Sanu.to_string(),
          },
          Person {
            name: "Shilshad.to_string(),
          }
       ]
    
       peopel.run();
       people.walk();
    
       let elephants: Vec<Elephant> = vec![
          Elephant{
            name: "John.to_string(),
          },
          Elephant{
            name: "Sanu.to_string(),
          },
          Elephant{
            name: "Shilshad.to_string(),
          }
       ]
       elephant.walk();
       elephant.run();
    }
    
    
  • The above example implements a code which allows a vector to run a method if all its element can run the method.
  • The above code block will throw an error as the trait CanRun was implemented for structure elephant.

Comments