我有大量重复的数据转换,我希望尽可能地DRY起来。例如
struct A {
first: Option<f32>,
second: i64,
...
}
let data = vec![A{None, 1}, A{Some(2.), 3}, ...];
目前,我有相当重复的代码来计算每个字段的平均值。例如
let mean_first = data.iter().filter(|a| a.first.is_some()).map(|a| a.first.unwrap() ).sum::<f32>() / data.length() as f32;
let mean_second = data.iter().map(|a| a.second).sum::<i64>() / data.length() as f32;
实际上,该结构体可能有数百个混合类型和可选类型的数字字段,我希望为每个字段计算几种类型的统计信息。是否有可能定义一个函数,该函数接受Vec和字段成员T的名称,并返回这些成员的平均值,并处理浮点和整数值,可选或否?
如果有一种通过知道字符串名称来获取字段的编程方法,那么解决方案可能如下所示:
fn mean(vec: Vec<T>, field: String) -> f32 {
...
}
let mean_first = mean(data, "first");
let mean_second = mean(data, "second");
或更多的OO可能看起来像
let mean_first = data.mean("first");
let mean_second = data.mean("second");
如果不可能使用函数,那么宏是否适合这里?
一种方法是使用宏:
macro_rules! mean {
($v: expr, $f: expr, $ty: ty) => {
$v.iter().filter_map($f).sum::<$ty>() / $v.len() as $ty
};
}
,你可以这样使用:
struct Foo {
f: i32,
g: Option<i32>,
}
fn main() {
let m = mean!(v, |x| Some(x.f), i32);
let m = mean!(v, |x| x.g, i32);
let m = mean!(v, |x| Some(x.f as f32), f32);
let m = mean!(v, |x| x.g.map(|v| v as f64), f64);
}