在 Rust 中,如何定义将 Vec<T> 转换为 Vec<U> 的通用函数

Luc*_*ida 6 rust

我需要类似的东西:

fn my_convert<T, U>(v: &Vec<U>)->Vec<T>{
    v.iter().map(|&t|t).collect()
}
Run Code Online (Sandbox Code Playgroud)

当然,我认为只有内置数字类型的向量可以传递给函数。

编译器告诉我需要为 Vec 提供 FromIterator 特征

该特征std::iter::FromIterator<U>未针对 `std::vec::Vec 实现

然后,我添加了

impl<T, U> std::iter::FromIterator<U> for Vec<T>{
    fn from_iter<I>(iter:I)->Self where I: IntoIterator<Item=U>{
        Vec::<T>::new()    // just for test
    }
}
Run Code Online (Sandbox Code Playgroud)

std::iter::FromIterator<_>type 的特征的冲突实现std::vec::Vec<_>:注意:板条箱中的冲突实现alloc: - impl std::iter::FromIterator for std::vec::Vec;rustc(E0119)

众所周知,在C++中,这种转换是直接且直观的。我是 Rust 的初学者。我不知道如何定义上面这样的函数。我什至不知道它是否可以在 Rust 中实现,因为泛型类型特征的复杂性。

谢谢!

Sil*_*olo 16

RustFrom特征是您的通用目的“如何从 A 到 B”。如果有一个合理的方法从UT,那么T: From<U>就会被实施。考虑

fn my_convert<T, U>(v: Vec<U>) -> Vec<T>
where T: From<U> {
  v.into_iter().map(T::from).collect()
}
Run Code Online (Sandbox Code Playgroud)

请注意,我确实拥有该v向量的所有权。该From::from函数消耗它的参数,所以我们也应该消耗向量。您可以编写此函数的完全通用版本,该版本可与任意迭代器一起使用,然后可以更轻松地在拥有其数据的迭代器和仅借用数据的迭代器之间来回切换。

fn my_convert1<T, U, I>(v: I) -> Vec<T>
where T: From<U>,
      I: Iterator<Item=U> {
  v.map(T::from).collect()
}
Run Code Online (Sandbox Code Playgroud)

但到那时,你最好v.map(T::from).collect()直接编写,任何相当熟练的 Rust 程序员都会立即知道你在做什么。

这里需要注意一点,因为您已经提到您是一名 C++ 程序员。在 C++ 中,模板函数可以简单地按原样编写,然后,当调用者实例化它的一个版本时,编译器检查它是否可以。所以你在OP中提出的函数工作得很好,因为编译器只在调用它时检查它。Rust(实际上是大多数带有泛型的语言)不是这样的。

另一方面,在 Rust 中,当您编写函数时my_convert,Rust 会检查所有类型是否对齐。你不能编写一个只在某些时候起作用的函数。如果你说my_convert适用于所有 TU,那么它最好适用于所有它们,并且 Rust 的类型检查器和借用检查器将立即验证这一点。如果没有,那么你最好像我上面那样做并限制类型签名。如果您曾经使用过 C++20,您可以将特征视为与 C++20 中的“概念”功能有些相似。

  • 我什至想补充一点,您可以将 `I: Iterator&lt;Item = U&gt;` 更改为 `I: IntoIterator&lt;Item = U&gt;`,并在 `.map(..)` 之前添加 `.into_iterator()`。 (2认同)