我想定义一个函数来计算向量的中值,该向量包含f32或u32值,或者可能是所有数字类型。f32和u32是我当前的用例。
我认为我对泛型或特性的理解不够。我能做的最好的事情是在下面,我指定泛型类型参数T需要实现一些特性以允许数学运算。如果可能的话,我也想将返回类型转换为f32,而不是T.
fn median<T: Add<Output = T> + From<f32> + Div<Output = T>>(array: &Vec<T>) -> T {
if (array.len() % 2) == 0 {
let ind_left = array.len() / 2 - 1;
let ind_right = array.len() / 2;
(array[ind_left] + array[ind_right]) / 2.0
} else {
array[(array.len() / 2)]
}
}
但这在第5行有一个问题:
mismatched types
expected type parameter `T`
found type `{float}`rustcE0308
我可以使用map将一种类型的向量转换为另一种类型,但这感觉是不必要的工作。
第一个问题是2.0
是一个浮点文字,而不是T
。T
可以是实现指定特征的任何东西。
因此,您需要将2.0
转换为T
才能工作:
(array[ind_left] + array[ind_right]) / T::from(2.0)
然后您将遇到第二个问题,即array[ind_right]
试图将项目复制出去,但您没有告知对象可以被复制。这需要Copy
的附加绑定(或者Clone
然后是显式Clone
调用(。
如果可能的话,我也想将返回类型强制转换为f32,而不是T.
然后需要添加Into<f32>
的类型绑定。
事实上,我不认为From<f32>
是正确的或有用的:它可以让你转换2.0
,但最终从f32转换的只有f32和f44。
可能更有用的是能够转换为f32,然后在内部完全处理f32。这意味着你不需要其他特征绑定,只需要(和复制(:
fn median<T: Into<f32> + Copy>(array: &[T]) -> f32 {
if (array.len() % 2) == 0 {
let ind_left = array.len() / 2 - 1;
let ind_right = array.len() / 2;
(array[ind_left].into() + array[ind_right].into()) / 2.0
} else {
array[(array.len() / 2)].into()
}
}
这仍然不太好,因为Rust在实现From
时非常保守:只有u8、i8、u16和i16可以通过这种方式转换,因为单精度浮点(f32(只有24位精度,这意味着它不能表示每个32位整数。
铸造在Rust中不是通用的。
所以你可能想看看num
,它可能有适用于这种情况的数字转换特性。