Hi, hoping the community can help.
I'd like to consolidate some functions that only differ in their arguments. Here, I've made a trait (Direction
) that can abstract across a custom type (Cartestian
) and (f64, f64)
.
#[derive(Clone, Copy)]
struct Cartesian {
x: f64,
y: f64,
}
impl Cartesian {
fn new(x: f64, y: f64) -> Self {
Self { x, y }
}
}
trait Direction: Copy {
fn get_x(self) -> f64;
fn get_y(self) -> f64;
}
impl Direction for Cartesian {
fn get_x(self) -> f64 {
self.x
}
fn get_y(self) -> f64 {
self.y
}
}
impl Direction for (f64, f64) {
fn get_x(self) -> f64 {
self.0
}
fn get_y(self) -> f64 {
self.1
}
}
struct Beam;
impl Beam {
fn calc<D: Direction>(&self, dir: D) -> f64 {
// Contrived for example's benefit
dir.get_x() + dir.get_y()
}
}
fn main() {
let b = Beam;
println!("{}", b.calc(Cartesian::new(5.0, 8.0)));
println!("{}", b.calc((5.0, 8.0)));
}
This works well.
However my problem lies with a "calc many" function for Beam
; it is allowed to take a slice of Cartesian
or two slices of f64
to get multiple coordinate pairs. (The actual implementation iterates over the input coords, so it seems best to make an iterator trait but I may be wrong.)
Here is an attempt:
impl Beam {
// This is in addition to the other function
fn calc_many<D: Direction, T>(&self, dirs: &T) -> Vec<f64>
where
for<'a> &'a T: IntoIterator<Item = &'a D>,
{
dirs.into_iter()
.map(|dir| dir.get_x() + dir.get_y())
.collect()
}
}
fn main() {
let v = vec![
Cartesian::new(1.0, 1.0),
Cartesian::new(1.0, 2.0),
Cartesian::new(2.0, 3.0),
];
println!("{:?}", b.calc_many(&v));
let a = [
Cartesian::new(1.0, 1.0),
Cartesian::new(1.0, 2.0),
Cartesian::new(2.0, 3.0),
];
println!("{:?}", b.calc_many(&a));
let a = [(1.0, 1.0), (1.0, 2.0), (2.0, 3.0)];
println!("{:?}", b.calc_many(&a));
let a = [1.0, 1.0, 2.0];
let a2 = [1.0, 2.0, 3.0];
let i = a
.into_iter()
.zip(a2.into_iter())
.map(|(a, b)| Cartesian::new(a, b));
println!("{:?}", b.calc_many(i));
}
This almost works, but attempting to use i
at the bottom of main
doesn't work. Besides, I'd like users to be able to pass in slices instead of iterators.
What's the best way to make a "calc many" function that can take a slice of an appropriate input (here Direction
), or a tuple of slices (e.g. (&[1.0, 1.0, 2.0], &[1.0, 2.0, 3.0])
? I have tried to make another trait without much luck.
(For additional context, here's the code I'm trying to consolidate. I want to make any new code able to be used with rayon
but I figured a normal iterator will help me understand how this works.)