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
Post a Comment