如何在 Rust 中“矢量化”函数

How to "vectorize" a function in Rust

提问人:YEp d 提问时间:9/1/2023 更新时间:9/1/2023 访问量:65

问:

假设我想将一个对集合的两个元素进行操作的函数转换为对两个集合进行元素操作的函数。

例如,我想将一个函数将两个数字相加,变成一个函数,该函数接受两个数字集合并将数字按元素相加。为了在不重复代码的情况下做到这一点,我尝试实现一个接受闭包的函数:

fn vectorize<F, H, U, J>(f: F) -> impl Fn(H, H) -> J
where
    F: FnMut((H::Item, H::Item)) -> U,
    H: IntoIterator,
    J: FromIterator<U>
    { |x, y| {x.into_iter().zip(y).map(f).collect()} }

comipler 给出:

error[E0507]: cannot move out of `f`, a captured variable in an `Fn` closure
  --> src/main.rs:10:40
   |
5  | fn vectorize<F, H, U, J>(f: F) -> impl Fn(H, H) -> J
   |                          - captured outer variable
...
10 |     { |x, y| {x.into_iter().zip(y).map(f).collect()} }
   |       ------                           ^ move occurs because `f` has type `F`, which does not implement the `Copy` trait
   |       |
   |       captured by this `Fn` closure

这不起作用,因为闭包已通过该方法移出返回的闭包。但实际上,这样的函数应该是可以编写的,因为无论在不同的迭代器上使用多少次,它都是有效的。fmapfFnMut

如何编写这种类型的函数,使其不会导致此类错误?

防锈 封盖

评论


答:

4赞 cafce25 9/1/2023 #1

你想在这里改变三件事。

  1. 你不能把a转换成a,所以你也必须返回。FnMutFnimpl FnMut
  2. 在闭包之前添加,以便它拥有movef
  3. 你不能传递给 map,因为这必然会移动它,但你不能从一个只在你的代码或固定代码中实现的闭包中移动。相反,传递对它的引用(只有可变引用也实现 FnMut,并且要传递可变引用,您还必须使可变):fFnFnMutf
fn vectorize<F, H, U, J>(mut f: F) -> impl FnMut(H, H) -> J
where
    F: FnMut((H::Item, H::Item)) -> U,
    H: IntoIterator,
    J: FromIterator<U>,
{
    move |x, y| x.into_iter().zip(y).map(&mut f).collect()
}

您可能还需要添加第二个类型参数,以便也可以将 2 种不同类型的集合与可能不同的类型合并。: IntoIterator

评论

0赞 YEp d 9/1/2023
为什么在这种情况下需要可变?另外,一旦 x 和 y 被移动到闭包中,这个函数会消耗它们吗?f
2赞 cafce25 9/1/2023
1)看到我的编辑,2)是的,但这与任何其他闭包没有什么不同,特别是无论你是否添加,它都不会改变,这就是函数参数的工作方式,书中所述move