问题中的代码无法编译,因为
f64
没有
borrow()
方法。此外,它接受的切片不需要是可变的,因为我们没有改变它。这是一个经过修改可以编译和工作的版本:
fn mean(arr: &[f64]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num - mean) / i;
}
mean
}
我们在循环
arr
时指定
&num
,以便
num
的类型为
f64
而不是对
f64
的引用。这个片段可以使用两者,但省略它将破坏通用版本。
为了使相同的函数接受浮点数和整数,它的参数需要是
通用的。理想情况下,我们希望它接受任何可转换为
f64
的类型,包括
f32
或定义了这种转换的用户定义类型。像这样:
fn mean<T>(arr: &[T]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num as f64 - mean) / i;
}
mean
}
这段代码无法编译,因为对于任意类型的
x
,
x as f64
未定义。相反,我们需要在
T
上定义一个trait bound,以定义将
T
值转换为
f64
的方法。这正是
Into
trait的目的;每个实现
Into<U>
的类型
T
都定义了一个
into(self) -> U
方法。将
T: Into<f64>
指定为trait bound,给我们返回
f64
的
into()
方法。
我们还需要请求
T
为
Copy
,以防止从数组中读取值“消耗”该值,即尝试将其移出数组。由于原始数字(如整数)实现了
Copy
,因此对我们来说这是可以的。工作代码如下:
fn mean<T: Into<f64> + Copy>(arr: &[T]) -> f64 {
let mut i = 0.0;
let mut mean = 0.0;
for &num in arr {
i += 1.0;
mean += (num.into() - mean) / i;
}
mean
}
fn main() {
let val1 = mean(&vec![4.0, 5.0, 3.0, 2.0]);
let val2 = mean(&vec![4, 5, 3, 2]);
println!("The means are {} and {}", val1, val2);
}
请注意,这仅适用于定义了无损转换为f64
的类型。因此,它适用于u32
,i32
(如上例所示)和更小的整数类型,但不接受例如i64
或u64
的向量,因为它们无法无损地转换为f64
。
还要注意,这个问题很适合函数式编程习惯,比如enumerate()
和fold()
。虽然超出了这个已经很长的答案的范围,但编写这样的实现是一种难以抵制的练习难以抵制。
f64
,但也接受整数输入。 - @MatthieuM - user4815162342num
库,我认为这个库没有被充分利用。它定义了zero
和one
特性,可以用于像sum
和product
这样的函数。 - user25064