found a function to compute a mean并一直在玩它。下面的代码段运行,但是如果输入中的数据从float更改为int,则会发生错误。如何使它与浮点数和整数一起使用?

use std::borrow::Borrow;

fn mean(arr: &mut [f64]) -> f64 {
    let mut i = 0.0;
    let mut mean = 0.0;
    for num in arr {
        i += 1.0;
        mean += (num.borrow() - mean) / i;
    }
    mean
}

fn main() {
    let val = mean(&mut vec![4.0, 5.0, 3.0, 2.0]);
    println!("The mean is {}", val);
}

最佳答案

问题中的代码无法编译,因为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
}

我们在遍历&num时指定arr,以便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 as f64定义x。相反,我们需要在T上绑定(bind)一个特征,该特征定义了一种将T值转换为f64的方法。这正是 Into trait的目的;实现T的每种类型Into<U>都定义一个into(self) -> U方法。将T: Into<f64>指定为特征绑定(bind)将为我们提供into()方法,该方法返回f64

我们还需要将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的类型。因此,它将适用于u32i32(如上例中所示)和较小的整数类型,但将不接受i64u64的向量,这些向量不能无损地转换为f64

还要注意,此问题很好地适用于函数式编程习惯用法,例如 enumerate() fold() 。尽管不在这个已经很久的答案的范围内,但是写出这样的实现是一个练习hard to resist

关于rust - 如何允许函数使用整数或浮点数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42896665/

10-10 22:48