Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you map a c# abstract class to Rust?

Tags:

c#

rust

traits

Possibly a poorly worded question, but here goes an example:

given these structs;

pub struct Poll {
    _lat: f64,
    _lon: f64,
    _at: i64,
    _heading: f64,
    _speed: f64,
}

pub struct Waypoint {
    _lat: f64,
    _lon: f64,
}

and this trait;

pub trait CoordMeasure {
    fn dist_to(&self, other: &Self ) -> f64;
}

how do I avoid duplicating this code like I have done?

impl CoordMeasure for Poll {
    fn dist_to(&self, other: &Poll) -> f64 {
        super::core::distance(self, other)
    }
}

impl CoordMeasure for Waypoint {
    fn dist_to(&self, other: &Waypoint) -> f64 {
        super::core::distance(self, other)
    }
}

I have two calls to the same function distance.

pub fn distance<T: Coord>(a: &T, b: &T ) -> f64 {
        let lat1_rads = (90.0 - a.lat()).to_radians();
        let lat2_rads = (90.0 - b.lat()).to_radians();
        let lon_rads = (b.lon() - a.lon()).to_radians();

        let cos_of_lat1 = lat1_rads.cos();
        let cos_of_lat2 = lat2_rads.cos();

        let sin_of_lat1 = lat1_rads.sin();
        let sin_of_lat2 = lat2_rads.sin();

        let cos_of_lons = lon_rads.cos();
        let equation = ((cos_of_lat2 * cos_of_lat1) + (sin_of_lat2 * sin_of_lat1 *    cos_of_lons)).acos();
        6334009.6 * equation
}

It's just one line of code that's being repeated, but it could be more in a better example. In C# this code would be written once in an abstract class that Waypoint and Poll were derived from. What's the idiomatic Rust way of handling this situation?

like image 681
Bruce Avatar asked Sep 30 '22 15:09

Bruce


1 Answers

Generic implementations are possible:

impl<T: Coord> CoordMeasure for T {
    fn dist_to(&self, other: &T) -> f64 {
        super::core::distance(self, other)
    }
}

But in this particular case, you should just drop CoordMeasure altogether and implement this on Coord as a default method:

trait Coord {
    …
    fn dist_to(&self, other: &Self) -> f64 {
        super::core::distance(self, other)  // or move its contents in here
    }
}

You might also want to make it so that it can cope with other types of other (I don’t see any immediate reason why other must be the same type as self:

fn dist_to<Other: Coord>(&self, other: &Other) -> f64 {
    let lat1_rads = (90.0 - self.lat()).to_radians();
    let lat2_rads = (90.0 - other.lat()).to_radians();
    let lon_rads = (b.lon() - self.lon()).to_radians();

    let cos_of_lat1 = lat1_rads.cos();
    let cos_of_lat2 = lat2_rads.cos();

    let sin_of_lat1 = lat1_rads.sin();
    let sin_of_lat2 = lat2_rads.sin();

    let cos_of_lons = lon_rads.cos();
    let equation = ((cos_of_lat2 * cos_of_lat1) + (sin_of_lat2 * sin_of_lat1 *    cos_of_lons)).acos();
    6334009.6 * equation
}
like image 114
Chris Morgan Avatar answered Oct 04 '22 09:10

Chris Morgan