所以我有下面的代码片段,我想接受任意值的Vec
,并将这些值转换为f32。这是为了处理浮点数、整型数、无符号值等。
pub struct Vals {
// Our concrete values
mat: Vec<Vec<f32>>,
shape: (usize, usize),
name: String,
}
impl Vals {
pub fn from_vec<T: Into<f32>>(vec: Vec<T>, name: Option<String>) -> Self {
let s1 = vec.iter().len();
let mut as_mat: Vec<Vec<f32>> = Vec::new();
let recasted = vec.iter().map(|&x| x as f32).collect();
as_mat.push(vec);
Vals {
mat: as_mat,
shape: (s1, 1),
name: name.unwrap_or(String::from("")),
}
}
我在下面这行遇到了一个问题:let recasted = vec.iter().map(|&x| x as f32).collect();
,它告诉我an
是expression can only be used to convert between primitive types or to coerce to a specific trait object
,但我认为我指定Into
trait可以处理这个问题?
我已经通读了From and Into Rust Documentation,但似乎没有什么可以帮助我解决我的问题。我看到它提到了how to create itself from another type, hence providing a very simple mechanism for converting between several types
,但我认为我可以处理这个。我主要是在寻找建议,要么重组我的代码,使之成为可能,或直接解决错误。
谢谢大家!
编辑:我根据@drewtato的建议重新构造了from_vec
函数,现在有了
pub fn from_vec<T: Into<f32>>(vec: Vec<T>, name: Option<String>) -> Self {
// `Vec` has a `len` method already
let s1 = vec.len();
let recasted = vec.into_iter().map(|x| x.into()).collect();
// Don't need to create the empty `Vec`
let mat = vec![recasted];
Vals {
mat,
shape: (s1, 1),
name: name.unwrap_or_default(),
}
}
但在我的测试案例中
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec(){
let v1= vec![1,2,3];
let res = Vals::from_vec(v1, None);
}
}
但似乎并不像我想的那样我要
the trait bound `f32: std::convert::From<i32>` is not satisfied
[E0277] the trait `std::convert::From<i32>` is not implemented for
`f32` Help: the following other types implement trait
`std::convert::From<T>`: <f32 as std::convert::From<bool>> <f32 as
std::convert::From<i16>> <f32 as std::convert::From<i8>> <f32 as
std::convert::From<u16>> <f32 as std::convert::From<u8>> Note:
required for `i32` to implement `std::convert::Into<f32>` Note:
required for `f32` to implement `std::convert::TryFrom<i32>`
我不明白我阅读这篇文章是因为强制转换没有实现,但是如果我实现了强制转换,那不是违背了泛型的目的吗?
2条答案
按热度按时间gc0ot86w1#
as
是一个特殊的内建函数,可以转换原语和其他一些东西,但是它没有连接到任何trait,所以你不能在泛型上使用它。这与几乎所有其他操作符不同,它们都与trait相连。+
对应于std::ops::Add
trait,*
是std::ops::Deref
trait,甚至for
循环使用std::iter::IntoIterator
trait。Into
是一个完全正常的trait,与任何操作符语法无关。作为一个trait,你可以用它来限制泛型,你已经做到了,然后在泛型值上使用它的方法。但它根本不知道as
。要使用
T: Into
,您需要使用Into::into
:如果您希望能够接受任何可以用
as
转换的值,您可以使用num-traits crate,它提供了AsPrimitive
trait。该trait仍然不知道as
是什么,但它们有一个方法as_
,该方法已经为每一个可能的转换实现,以在内部调用as
。x.as_()
大致相当于x as _
。这与
Into
略有不同,因为您可以使用as
而不是Into
从f64
转换为f32
,并且标准库之外的类型可能实现Into<f32>
,但很少实现AsPrimitive
。另一个错误是因为
Into::into
获取了它正在转换的值的所有权。对于实现了Copy
的类型,比如数字原语,你可以直接解引用它们来获得一个拥有的值。您可以通过进一步限制泛型来使其在函数中工作。注意,如果你这样做,你应该take your parameter by reference。
另一种选择是,如果您希望能够接受不是
Copy
的值,则可以使用into_iter
来始终拥有值。我在第一个片段中使用了它,这里再次使用。但是,这限制了您获得
Vec
的所有权,并且不能在其位置上使用&[T]
。你还可以做一些直接等价的修改。这是整个函数的清理。
xt0899hw2#
您可以使用
into
将值转换为f32