如何以函数式风格编写延迟评估的双循环?

How do I write a lazily evaluated double for loop in a functional style?

如何在 Rust 中以函数式风格编写延迟计算的双 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`.

进一步说明

要解决此问题,您可以预先借用 &numbers,然后仅隐藏 numbers。然后,您可以将 move 添加到第二个闭包中。

fn main() {
    let numbers: Vec<i32> = (1..100).collect();
    let len = numbers.len();

    let numbers = &numbers;

    let _sums_of_pairs: Vec<_> = (0..len)
        .map(|j| ((j + 1)..len).map(move |k| numbers[j] + numbers[k]))
        .flatten()
        .collect();
}

我建议您使用迭代器而不是索引编写更多地道的 Rust 代码。就是更简单。

fn main() {
    let numbers: Vec<i32> = (1..100).collect();

    let _sums_of_pairs: Vec<_> = numbers.iter()
        .enumerate()
        .flat_map(|(j, &num)| numbers[j + 1..].iter().map(move |&k| k + num))
        .collect();
}

如果您仍想使用索引(请注意,效果会差很多),这会起作用:

fn main() {
    let numbers: Vec<i32> = (1..100).collect();
    let len = numbers.len();

    let _sums_of_pairs: Vec<_> = (0..len)
        .flat_map(|j| {
            let numbers = &numbers;
            ((j + 1)..len).map(move |k| numbers[j] + numbers[k])
        })
        .collect();
}

更新: 另外,我写了一个基准来表明:

  1. 我的版本不比@vallentin 慢。差别是1-2微秒。
  2. Itertools 版本不是“慢 100 倍”,而是慢了 4/3 倍。

基准可用 gist。 这是结果(itertools - 使用 itertools crate,indexing - 来自 vallentin 和 OP 偏好的版本,以及 iterators - 我的迭代器解决方案):

itertools/100           time:   [12.781 us 12.805 us 12.831 us]
Found 13 outliers among 100 measurements (13.00%)
  13 (13.00%) low severe
itertools/200           time:   [48.211 us 48.693 us 49.071 us]

indexing/100            time:   [9.9299 us 9.9378 us 9.9467 us]
Found 14 outliers among 100 measurements (14.00%)
  1 (1.00%) low mild
  1 (1.00%) high mild
  12 (12.00%) high severe
indexing/200            time:   [39.582 us 39.654 us 39.720 us]
Found 2 outliers among 100 measurements (2.00%)
  1 (1.00%) high mild
  1 (1.00%) high severe

iterators/100           time:   [9.7633 us 9.7809 us 9.8010 us]
Found 1 outliers among 100 measurements (1.00%)
  1 (1.00%) high severe
iterators/200           time:   [38.732 us 38.785 us 38.840 us]
Found 5 outliers among 100 measurements (5.00%)
  3 (3.00%) high mild
  2 (2.00%) high severe