【发布时间】:2021-03-23 07:01:05
【问题描述】:
如何在 Rust 中以函数式风格编写一个惰性求值的 double for 循环?
借来的值是 usize 类型,应该可以很容易地复制。
fn main() {
let numbers: Vec<i32> = (1..100).collect();
let len = numbers.len();
let _sums_of_pairs: Vec<_> = (0..len)
.map(|j| ((j + 1)..len).map(|k| numbers[j] + numbers[k]))
.flatten()
.collect();
}
error[E0373]: closure may outlive the current function, but it borrows `j`, which is owned by the current function
--> src/bin/example.rs:6:37
|
6 | .map(|j| ((j + 1)..len).map(|k| numbers[j] + numbers[k]))
| ^^^ - `j` is borrowed here
| |
| may outlive borrowed value `j`
|
note: closure is returned here
--> src/bin/example.rs:6:18
|
6 | .map(|j| ((j + 1)..len).map(|k| numbers[j] + numbers[k]))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `j` (and any other referenced variables), use the `move` keyword
|
6 | .map(|j| ((j + 1)..len).map(move |k| numbers[j] + numbers[k]))
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0373`.
补充说明
- 我知道
Itertools::combinations(2)可以完成这项工作。但是,我不想使用它,因为(1)我想知道如何自己做,(2)这可能是我的代码很慢的原因,我想消除那个来源。 (更新:Itertools::tuple_combinations<(_, _)>()的速度要快得多,而且可以让你以函数式的方式编写代码。) - 我也试过先把它收集到一个容器里。
(0..len).collect::<Vec<_>>().iter().cloned().map(...) - 我尝试了建议的
move,但随后numbers也被移动,因此在下一个循环中不可用。 - 在此代码示例中的任何地方都没有发生线程或异步。
- Shepmaster 在this 回答中说我无法对闭包进行生命周期注释。
- 我不写两个提前返回的原始循环的原因是,如果我想说,运行
.any()来查找是否存在特定值,我必须将两个循环移动到一个单独的函数,因为我不能将return true;放入循环中,除非它位于单独的函数中。
【问题讨论】:
-
你需要使用移动闭包:
move |k| numbers[j] + numbers[k] -
“我尝试了建议的移动,但数字也被移动了,因此在下一个循环中不可用。” ...我得到的错误是:“无法移出
numbers,FnMut闭包中的捕获变量” -
附带说明,
.map(...).flatten()可以简化为.flat_map()。