you don't need vector specifically, reduce()
is defined in Iterator
. this will work for any iterators that yields i32:
fn reducer(v: impl Iterator<Item = i32>, reduce_fn: fn(i32, i32) -> i32) -> I32 {
v.reduce(reduce_fn).unwrap_or(0)
}
then you can use the Fn
trait bound, instead of a regular function pointer:
fn reducer(v: impl Iterator<Item = i32>, reduce_fn: impl Fn(i32, i32) -> i32) -> I32 {
v.reduce(reduce_fn).unwrap_or(0)
}
this will accept Iterator<Item = i32>
directly, but slice::iter()
will give you an Iterator<Item = &i32>
, you can use Iterator::cloned()
to get an Iterator<Item = i32>
, like this:
let v = &[1, 2, 3, 4];
let r = reducer(v.iter().cloned(), add);
to accept both Iterator<Item = i32>
and Iterator<Item = &i32>
, you'll need a trait that both &i32
and i32
implement. you can define a marker trait yourself, or there's a trait in the standard library with reflexivity, i.e. std::borrow::Borrow<i32>
, (although it feels kind of wrong to abuse Borrow
here, due to the semantical implications).
also, you can use IntoIterator
in place of Iterator
so the function can also accept a slice or array directly (no need to call iter()
on it)
so the final form is something like this:
// marker trait for i32 and &i32
trait ToI32 { fn to_i32(&self) -> i32; }
impl ToI32 for i32 { fn to_i32(self) -> i32 { self } }
impl<'a> ToI32 for &'a i32 { fn to_i32(self) -> i32 { *self } }
// generic function
fn reducer<I, F>(values: I, f: F) -> i32
where
I: IntoIterator,
I::Iterm: ToI32,
F: Fn(i32, i32) -> i32
{
values.into_iter().map(ToI32::to_i32).reduce(f).unwrap_or(0)
}
// example usage
fn main() {
let values = [1, 2, 3, 4];
// slice
reducer(&values[..], add);
// array
reducer(values, add);
let values = vec![1, 2, 3, 4];
// Iterator<Item = &i32>
reducer(values.iter(), add);
// Iterator<Item = i32>
reducer(values.into_iter(), add);
}