将usize转换为f32

5

我已经实现了以下函数,用于计算序列的平均值:

fn mean<T, R>(seq: &[T]) -> R
    where R: Div<R, Output=R> + From<T> + From<usize> + Sum<R>
{
    let total: R = seq.iter().map(|&x| R::from(x)).sum()
    let size = R::from(seq.len())
    total / size
}

然而,当转换由 seq.len() 返回的 usize 时,我遇到了困难。

let numbers = vec![10, 20, 30, 40, 50, 60];
let result: f32 = mean(&numbers);
println!("{:?}", result);

5  | fn mean<T, R>(seq: &[T]) -> R
   |    ----
6  |     where R: Div<R, Output=R> + From<T> + From<usize> + Sum<R>
   |                                           ----------- required by this bound in `mean`
...
15 |     let result: f32 = mean(&numbers);
   |                       ^^^^ the trait `std::convert::From<usize>` is not implemented for `f32`

由于我在使用traits方面还是个初学者,所以这个问题让我很困扰。是否有解决这个特定问题的方法?(如果有的话)

2个回答

2
问题在于`f32`没有实现`From`。它实现了`From`、`From`、`From`和`From`。这是因为`f32`不能精确表示更大整数的所有值。
你可能想要使用`as`转换,允许一些精度损失。不幸的是,你不能在泛型类型上使用`as`,只能在原始类型上使用。
你可以编写一个trait来手动执行所有必要的`as`转换...但当然有crate解决!使用`num_traits::cast::AsPrimitive`,你的代码变成了:
fn mean<T, R>(seq: &[T]) -> R
    where R: Div<R, Output=R> + Sum<R> + Copy + 'static,
          T: AsPrimitive<R>,
          usize: AsPrimitive<R>
{
    let total: R = seq.iter().map(|&x| x.as_()).sum();
    let size = seq.len().as_();
    total / size
}

我已经添加了"Copy"约束,这是你的代码中可能遗漏的部分,并且还为"R"添加了"static",这是"AsPrimitive"所必需的。

请在回答问题之前搜索重复内容并标记为重复。 - Shepmaster

1
无法用 f32 格式表示每个可能的 i32 值。这就是为什么提供了 f32From 特质实现,仅支持 i16/u16/i8/u8i32f32 具有相同数量的字节,但通常 f32 会花费一些字节来表示指数,因此它不能表示所有来自 i32 的数字。单精度浮点格式

请在回答问题之前搜索重复内容并标记。 - Shepmaster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接