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值