Generics 均值函数的Rust泛型语法

Generics 均值函数的Rust泛型语法,generics,math,syntax,rust,Generics,Math,Syntax,Rust,我试图写一个函数,它取一部分数字并计算平均值 我尝试使用来自的想法,但出现了一个错误 我的代码是: extern crate num; use num::{FromPrimitive, Zero}; use std::ops::{Add, Div}; fn main() { let mut numbers = [10, -21, 15, 20, 18, 14, 18]; let err = "Slice is empty."; println!("Mean is {

我试图写一个函数,它取一部分数字并计算平均值

我尝试使用来自的想法,但出现了一个错误

我的代码是:

extern crate num;

use num::{FromPrimitive, Zero};
use std::ops::{Add, Div};

fn main() {
    let mut numbers = [10, -21, 15, 20, 18, 14, 18];
    let err = "Slice is empty.";

    println!("Mean is {:.3}", mean(&numbers).expect(err));
}

fn mean<T>(numbers: &[T]) -> Option<f64>
where
    T: Copy + Zero + Add<T, Output = T> + Div<T, Output = T> + FromPrimitive,
{
    match numbers.len() {
        0 => None,
        _ => {
            let sum = numbers.iter().sum: ();
            let length = FromPrimitive::from_usize(numbers.len()).unwrap();
            Some(sum / length)
        }
    }
}
有没有办法不使用实验特征就编写通用平均函数

当编译器无法确定fn sumself->S的类型时,您需要编写let foo:Bar=baz.sum;或者让foo=baz.sum:

如果您确定T始终是某种类型的数字原语,那么应该使用let sum从sum中收集一个拥有的类型:T=numbers.iter.cloned.sum;并将core::iter::Sum绑定到T。否则,您可能需要使用引用

您可以让您的函数在返回选项时更通用一点,但是如果您真的想返回选项,您应该使用ToPrimitive特性将T强制转换为f64。喜欢

当编译器无法确定fn sumself->S的类型时,您需要编写let foo:Bar=baz.sum;或者让foo=baz.sum:

如果您确定T始终是某种类型的数字原语,那么应该使用let sum从sum中收集一个拥有的类型:T=numbers.iter.cloned.sum;并将core::iter::Sum绑定到T。否则,您可能需要使用引用

您可以让您的函数在返回选项时更通用一点,但是如果您真的想返回选项,您应该使用ToPrimitive特性将T强制转换为f64。喜欢


您在泛型函数中执行两种不同的操作:

求和切片中的所有值:您需要通过向泛型类型参数添加求和边界来判断元素是可求和的。 具有2个元素的除法运算:需要将泛型类型转换为f64或任何要限制的浮点类型。因为您使用的是num-crate,所以我添加了ToPrimitive作为边界,它告诉您可以将泛型类型转换为基元类型。 以下是实施方案:

fn平均数:&'a[T]->选项 哪里
T:ToPrimitive+Sum您在通用函数中执行两种不同的操作:

求和切片中的所有值:您需要通过向泛型类型参数添加求和边界来判断元素是可求和的。 具有2个元素的除法运算:需要将泛型类型转换为f64或任何要限制的浮点类型。因为您使用的是num-crate,所以我添加了ToPrimitive作为边界,它告诉您可以将泛型类型转换为基元类型。 以下是实施方案:

fn平均数:&'a[T]->选项 哪里
T:ToPrimitive+Sum其他答案可能会帮助您解决一般编写此函数的实际问题

不过,您所问的实际错误只是一个语法错误。你写了这个:

let sum = numbers.iter().sum: ();
但几乎可以肯定的是,他打算写:

let sum = numbers.iter().sum();
编译器看到了您意外包含的:并认为您正在尝试使用类型归属。类型归属是在表达式中内联使用类型注释的语法,而不仅仅是在变量声明中

您所写的内容非常类似于:

let sum: () = numbers.iter().sum;

如果要在rustc夜间构建中启用类型归属,则错误会发生变化,因为现在编译器会告诉您sum是一个函数,并且肯定没有类型

其他答案可能会帮助您解决一般编写此函数的实际问题

不过,您所问的实际错误只是一个语法错误。你写了这个:

let sum = numbers.iter().sum: ();
但几乎可以肯定的是,他打算写:

let sum = numbers.iter().sum();
编译器看到了您意外包含的:并认为您正在尝试使用类型归属。类型归属是在表达式中内联使用类型注释的语法,而不仅仅是在变量声明中

您所写的内容非常类似于:

let sum: () = numbers.iter().sum;
如果要在rustc夜间构建中启用类型归属,则错误会发生变化,因为现在编译器会告诉您sum是一个函数,并且肯定没有类型

这个怎么样:

use std::iter::Sum;

fn main() {
    let err = "Slice is empty.";

    // Test vector of integers
    let numbers = vec![10i32, -21, 15, 20, 18, 14, 18];
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));

    // Test vector of floating point numbers
    let numbers = vec![10f64, -21f64, 15f64, 20f64, 18f64, 14f64, 18f64];
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));

    // Test empty vector
    let numbers: Vec<i32> = Vec::new();    
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));
}

fn mean<T, I: Iterator<Item = T>>(iter: I) -> Option<f64>
where
    T: Into<f64> + Sum<T>,
{
    let mut len = 0;
    let sum = iter
        .map(|t| {
            len += 1;
            t
        })
        .sum::<T>();

    match len {
        0 => None,
        _ => Some(sum.into() / len as f64)
    }
}
感谢我的朋友Sven的代码贡献。

这个怎么样:

use std::iter::Sum;

fn main() {
    let err = "Slice is empty.";

    // Test vector of integers
    let numbers = vec![10i32, -21, 15, 20, 18, 14, 18];
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));

    // Test vector of floating point numbers
    let numbers = vec![10f64, -21f64, 15f64, 20f64, 18f64, 14f64, 18f64];
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));

    // Test empty vector
    let numbers: Vec<i32> = Vec::new();    
    println!("Mean is {:.3}", mean(numbers.into_iter()).expect(err));
}

fn mean<T, I: Iterator<Item = T>>(iter: I) -> Option<f64>
where
    T: Into<f64> + Sum<T>,
{
    let mut len = 0;
    let sum = iter
        .map(|t| {
            len += 1;
            t
        })
        .sum::<T>();

    match len {
        0 => None,
        _ => Some(sum.into() / len as f64)
    }
}

感谢我的朋友Sven的代码贡献。

如果我不能使用整数类型作为输入,为什么要使用通用平均值方法?在这个特定的用例中,可以使用整数数组u8、i32或u64作为输入。唯一的缺点是除法截断,即println!{.3},u永远不会显示浮点数。当然,但不幸的是,这会破坏均值函数的质量。你说得对,@ÖmerErden。我以适当的方式更新了答案。谢谢@谢谢你的提示。我认为最好返回选项,因为整数数组的平均值很可能是一个浮点数,我不想截断答案。如果我不能使用整数类型作为输入,为什么要使用通用平均值方法?在这个特定的用例中,可以使用整数数组u8、i32或u6
4作为输入。唯一的缺点是除法截断,即println!{.3},u永远不会显示浮点数。当然,但不幸的是,这会破坏均值函数的质量。你说得对,@ÖmerErden。我以适当的方式更新了答案。谢谢@谢谢你的提示。我认为最好返回选项,因为整数数组的平均值很可能是浮点数,我不想截断答案。您链接的问题不建议写sum:。这在Rust today中是无效的语法,我只能假设这是一种推断长度类型并自己求和的打字错误。你们会明白为什么编译器不能做到这一点。扰流板:可能有许多类型实现num::FromPrimitive。可能有许多类型实现std::iter::Sum。就像可能有许多类型实现std::ops::Div一样,这是因为无法推断长度的类型。要进行推断,您必须确保没有歧义。密切相关:您链接的问题不建议编写sum:。这在Rust today中是无效的语法,我只能假设这是一种推断长度类型并自己求和的打字错误。你们会明白为什么编译器不能做到这一点。扰流板:可能有许多类型实现num::FromPrimitive。可能有许多类型实现std::iter::Sum。就像可能有很多类型实现std::ops::Div一样,这是因为无法推断长度的类型。要使推断有效,您必须确保没有歧义。高度相关:非常感谢。在多年的Python学习中,我惊讶于这些特性能如此迅速地变得如此复杂。我永远不会明白我需要第三方库中的零和ToPrimitive这样的特性来做一些看似简单的事情,比如取一些数字的平均值。@blokeley取一些数字的平均值-这就是问题所在:你没有取一些数字的平均值。您使用的是可以表示某一组属性的任何泛型类型的平均值。在Python中,您可以将字符串集合传递给等效函数,并获得运行时错误。等效的Rust代码强制执行编译代码时所做的任何操作都是有效的。您可以创建自己的特性,并仅为数字实现它,以降低此函数的表面复杂性。非常感谢。在多年的Python学习中,我惊讶于这些特性能如此迅速地变得如此复杂。我永远不会明白我需要第三方库中的零和ToPrimitive这样的特性来做一些看似简单的事情,比如取一些数字的平均值。@blokeley取一些数字的平均值-这就是问题所在:你没有取一些数字的平均值。您使用的是可以表示某一组属性的任何泛型类型的平均值。在Python中,您可以将字符串集合传递给等效函数,并获得运行时错误。等效的Rust代码强制执行编译代码时所做的任何操作都是有效的。您可以创建自己的trait并仅针对数字实现它,以降低此函数的明显复杂性。此解决方案不适用于isize或usize值此解决方案不适用于isize或usize值