泛型类型,不同于输入类型,作为函数的返回值



我试图在Rust中创建一个解析器,读取我们模拟的输出文件,找到给定变量名称的正确块,并返回该块的内容,该块可以是单个int或int或float的向量,由给定的维度确定。

然而,我无法找到一种方法来使用泛型类型T作为对i32和f64数字使用相同函数的方法。

我不明白如何以这种方式使用泛型。

我今天已经开始学习Rust了,所以请像我5岁一样向我解释解决方案。

我的理解问题的简化版本如下:

fn parse_b2f<T>(dims: Vec<i32>) -> Result<Vec<T>, String> {
let nentries = dims.iter().fold(1, |res, a| res*a);
Ok(vec![nentries])
}
fn main() {
let dims = vec![3720, 9];
let data = parse_b2f::<i32>(dims);
}

,但我得到expected type paramter T, found i32,指向parse_b2f函数最后一行的n个条目。如果我在main的函数调用中提供了i32,为什么T仍然被视为泛型,而不是i32?如果我将T更改为i32,则函数可以工作,但其思想是让用户传递类型(i32用于索引数组,f64用于实验数据数组等),而不必编写两个执行完全相同逻辑的函数。

我希望能够做一些像vec![nentries as T],因为i32和f64分开工作,但不与t。

我也考虑过使用enum:

enum Numbers {
I32(i32),
F64(f64),
}

代替T
fn parse_b2f<Numbers>(dims: Vec<i32>) -> Result<Vec<Numbers>, String> {...}
let data = parse_b2f::Numbers::I32(dims);

但是我真的不知道在这种情况下如何使用枚举

这在c++中可以工作,因为直到实例化才检查类型。在Rust中,泛型函数必须独立存在。parse_b2f函数不约束T,所以它必须可以为任何类型的T调用。这就是你得到错误的原因。你可以删除main()的整个体,你仍然会得到这个错误。

你所需要做的就是适当地约束T

在这个简单的例子中,你需要的是说"T必须是支持乘法运算的类型,其结果为T."您可以通过在std::ops::Mul<Output = T>上约束它来实现这一点。

此外,您需要一种方法来获取1的初始值,这可以通过helper特性来实现。(num-traits的箱子里有这样的特性)

最后,您要么需要将T约束在Copy上,要么使用.into_iter()代替.iter(),因为.iter()产生引用(必须复制引用以提供乘法操作),而.into_iter()通过消耗输入向量产生值。

下面是一个工作示例:

use std::ops::Mul;
use num_traits::One;
fn parse_b2f<T: One + Mul<Output = T>>(dims: Vec<T>) -> Result<Vec<T>, String> {
let nentries = dims.into_iter().fold(T::one(), |res, a| res*a);
Ok(vec![nentries])
}

还可以考虑更改函数以接受任何可以转换为TIterator(我们称之为IntoIterator<Item = T>)的内容。这允许传递Vec<T>,但也允许传递非拥有的迭代器:

use std::ops::Mul;
use num_traits::One;
fn parse_b2f<T: One + Mul<Output=T>>(dims: impl IntoIterator<Item = T>)
-> Result<Vec<T>, String>
{
let nentries = dims.into_iter().fold(T::one(), |res, a| res*a);
Ok(vec![nentries])
}

@cdhowie的回答很好地解释了原因,但不是使用他们显示的特征(也包括外部crate),你可以意识到你正在做与Iterator::product()相同的事情,只是使用它的特征-Product。您可以使用T: Product<T>into_iter(),或T: Product<&T>iter():

fn parse_b2f<T: std::iter::Product<T>>(dims: Vec<T>) -> Result<Vec<T>, String> {
let nentries = dims.into_iter().product();
Ok(vec![nentries])
}
// Or
fn parse_b2f<T: for<'a> std::iter::Product<&'a T>>(dims: Vec<T>) -> Result<Vec<T>, String> {
let nentries = dims.iter().product();
Ok(vec![nentries])
}

最新更新