我试图在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),
}
用
代替Tfn 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])
}
还可以考虑更改函数以接受任何可以转换为T
的Iterator
(我们称之为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])
}