假设我想将一个对集合的两个元素进行操作的函数,并将其转换为对两个集合按元素进行操作的函数。
例如,我想将一个将两个数字相加的函数转换为一个接受两个数字集合并将数字按元素相加的函数。为了在不重复代码的情况下做到这一点,我尝试实现一个接受闭包的函数:
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()} }
编译器给出:
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
这不起作用,因为闭包
f
已通过 map
方法从返回的闭包中移出。但实际上,这样的函数应该是可以编写的,因为 f
是 FnMut
并且无论在不同的迭代器上使用多少次它都将有效。
如何编写此类函数才不会导致此类错误?
您想在此处更改 2 件事。
FnMut
转换为 Fn
,因此您还必须返回 impl FnMut
。f
传递给映射,因为这必然会移动它,但您无法从仅实现代码中的 Fn
或固定代码中的 FnMut
的闭包中移动。相反,传递对它的引用: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()
}