This is my first post about Rust, So I'm going to keep it simple and at the same time a bit unrealistic, just to prove some points. ;-)
This article, as the title already revealed, is all about operator overloading. Specifically we will implement the following 4 traits.
- PartialEq
- PartialOrd
- Add
- Not
Our example, as other similar tutorials will be based upon a little bit of Geometry, specifically Points and Lines.
so we need to use the following
use std::cmp::Ordering;
use std::ops::Add;
use std::ops::Not;
- a Point will be a pair of cartesian coordinates (x,y)
#[derive(Copy, Clone)]
pub struct Point {
pub x: f32,
pub y: f32,
}
- a Line will be a pair of Points
#[derive(Copy, Clone)]
pub struct Line {
pub start: Point,
pub end: Point,
}
- The Point trait will just have a constructor
pub trait PointProperties {
fn new(x: f32, y: f32) -> Self;
}
impl PointProperties for Point {
fn new(x: f32, y: f32) -> Self {
return Self { x: x, y: y };
}
}
- The Line trait will have a constructor and a function that calculates the length of the Line. The length is calculated with the distance formula ( √(b.x-a.x)^2 + (b.y-a.y)^2 ) that (I assume) we all know from school.
pub trait LineProperties {
fn length(&self) -> f32;
fn new(a: Point, b: Point) -> Self;
}
impl LineProperties for Line {
fn length(&self) -> f32 {
return ((&self.end.x - &self.start.x).powf(2.0) + (&self.end.y - &self.start.y).powf(2.0))
.sqrt();
}
fn new(a: Point, b: Point) -> Self {
return Self { start: a, end: b };
}
}
First we will implement the equality. What is equality between two lines? In this case I am choosing to consider equal two lines that have the same length, regardless where they lie in our cartesian plane.
impl PartialEq for Line {
fn eq(&self, other: &Self) -> bool {
return &self.length() == &other.length();
}
}
Then we have the less than and greater than symbols. Again how can we compare two lines? Again I am choosing to compare the lengths of two lines, again regardless where they line in our cartesian plane
impl PartialOrd for Line {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.length().partial_cmp(&other.length())
}
}
Finally we down to the more unrealistic but handy nevertheless examples.
The not operator (!). In this case when applying the not operator in a line, flips the line along the y axis. This is achieved by simply reversing the signs of all cartesian coordinates that make up our line.
impl Not for Line {
type Output = Line;
fn not(mut self) -> Line {
self.start.x = -self.start.x;
self.start.y = -self.start.y;
self.end.x = -self.end.x;
self.end.y = -self.end.y;
return self;
}
}
Finally I implement the add operator (+). Again adding two lines doesn't make much sense, so what I am doing with the add operator is that I take the min_x, min_y and max_x, max_y for each pair of coordinates (start vs end)
impl Add for Line {
type Output = Line;
fn add(self, other: Self) -> Line {
let min_start_x: f32;
if &self.start.x > &other.start.x {
min_start_x = other.start.x;
} else {
min_start_x = self.start.x;
}
let min_start_y: f32;
if &self.start.x > &other.start.x {
min_start_y = other.start.y;
} else {
min_start_y = self.start.y;
}
let max_end_x: f32;
if &self.start.x < &other.start.x {
max_end_x = other.start.x;
} else {
max_end_x = self.start.x;
}
let max_end_y: f32;
if &self.start.x < &other.start.x {
max_end_y = other.start.y;
} else {
max_end_y = self.start.y;
}
let p_a = Point::new(min_start_x, min_start_y);
let p_b = Point::new(max_end_x, max_end_y);
return Line::new(p_a, p_b);
}
}
and too prove that everything is working this is our main function
fn main() {
println!("Points & Lines");
let point_a: Point = Point::new(0.0, 0.0);
let point_b: Point = Point::new(0.0, 10.0);
let line_a: Line = Line::new(point_a, point_b);
println!("line a has a length of {:?}", line_a.length());
let point_c: Point = Point::new(10.0, 10.0);
let point_d: Point = Point::new(10.0, 20.0);
let line_b: Line = Line::new(point_c, point_d);
println!("line b has a length of {:?}", line_b.length());
println!("are line a and b lengths equal? {:?}", line_a == line_b);
println!(
"is the mirror line's a length equal to line b {:?}",
!line_a == line_b
);
let line_c: Line = Line::new(point_a, point_d);
let line_d: Line = Line::new(point_b, point_c);
println!("line c has a length of {:?}", line_c.length());
println!("line d has a length of {:?}", line_d.length());
println!("is line c smaller than line b? {:?}", line_c < line_b);
println!(
"adding up lines give you a length of {:?}",
(line_c + line_b).length()
);
}
and our output
Points & Lines
line a has a length of 10.0
line b has a length of 10.0
are line a and b lengths equal? true
is the mirror line's a length equal to line b true
line c has a length of 22.36068
line d has a length of 10.0
is line c smaller than line b? false
adding up lines give you a length of 14.142136
I hope someone, out there, to find this piece useful. I certainly enjoyed writing it.