Rust错误[E0373]:闭包可能会超过当前函数,但它借用了`iteration_index`

时间:2019-02-08 16:20:20

标签: rust closures borrow-checker

我有两个itertools::MinMaxResult的向量。我需要遍历第一个向量,对于每个元素,遍历第二个向量,检查第一个向量的最小值是否等于第二个向量的任何元素的最大值,反之亦然。这是我尝试过的MCVE:

tuple

Link to the Playground with full code

我遇到以下错误:

use itertools::MinMaxResult; // itertools = "0.8.0"
use itertools::MinMaxResult::*;

pub fn mcve() -> Vec<(usize, usize)> {

    // dummy variables to make the MCVE compile
    let num_rows = 0;
    let num_cols = 0;
    let row_minmax: Vec<MinMaxResult<&u64>> = vec![];
    let col_minmax: Vec<MinMaxResult<&u64>> = vec![];

    // Problematic code:
    (0..num_rows)
            .flat_map(|row_index| {
                (0_usize..num_cols).filter_map(|col_index| {
                    match (row_minmax[row_index], col_minmax[col_index]) {
                        (MinMax(a, _b), MinMax(_c, d)) if a == d =>
                            Some((row_index, col_index)),
                        (MinMax(_a, b), MinMax(c, _d)) if b == c =>
                            Some((row_index, col_index)),
                        _ => None,
                    }
                })
            })
            .collect::<Vec<(usize, usize)>>()
}

如果我按照编译器的建议添加error[E0373]: closure may outlive the current function, but it borrows `row_index`, which is owned by the current function --> src/main.rs:15:48 | 15 | (0_usize..num_cols).filter_map(|col_index| { | ^^^^^^^^^^^ may outlive borrowed value `row_index` 16 | match (row_minmax[row_index], col_minmax[col_index]) { | --------- `row_index` is borrowed here | note: closure is returned here --> src/main.rs:15:17 | 15 | / (0_usize..num_cols).filter_map(|col_index| { 16 | | match (row_minmax[row_index], col_minmax[col_index]) { 17 | | (MinMax(a, _b), MinMax(_c, d)) if a == d => Some((row_index, col_index)), 18 | | (MinMax(_a, b), MinMax(c, _d)) if b == c => Some((row_index, col_index)), 19 | | _ => None, 20 | | } 21 | | }) | |__________________^ help: to force the closure to take ownership of `row_index` (and any other referenced variables), use the `move` keyword | 15 | (0_usize..num_cols).filter_map(move |col_index| { | ^^^^^^^^^^^^^^^^ ,则会出现两倍的错误,因此这无济于事。如何摆脱这个错误?

1 个答案:

答案 0 :(得分:0)

您的链接要点有很多典型的“与借位检查程序搏斗”错误。解决方法如下:

  • 按照编译器的建议使用move,但请确保所有移动的值都实现Copy
  • 类型为usize的迭代索引已经实现了Copy,因此这里无事可做。
  • 向量是有问题的,因此只需获取它们的不可变引用,然后将不可变引用传递给闭包即可。
  • 您的into_par_iter引起了不相关的所有权问题。只需使用par_iter,就可以遍历引用而不是实际值,并且在遍历矩阵时也不会破坏矩阵。

这里编译:

use itertools::MinMaxResult; // itertools = "0.8.0"
use itertools::MinMaxResult::*;
use itertools::Itertools;
use rayon::prelude::*; // rayon = "1.0.3"

pub fn find_saddle_points(input: &[Vec<u64>]) -> Vec<(usize, usize)> {
    let flattened_matrix: Vec<(&u64)> = input.into_par_iter().flatten().collect();
    if flattened_matrix.is_empty() {
        vec![]
    } else {
        let num_rows = input.len();
        let num_cols = input[0].len();

        let row_minmax: Vec<MinMaxResult<&u64>> = input
            .iter()
            .map(|row| row.iter().minmax())
            .collect::<Vec<MinMaxResult<&u64>>>();

        let input_tranpose: Vec<Vec<u64>> = (0_usize..num_cols)
            .into_par_iter()
            .map(|col_index| {
                (0_usize..num_rows)
                    .map(|row_index| input[row_index][col_index])
                    .collect::<Vec<u64>>()
            })
            .collect();

        // don't take ownership! 
        // Use `par_iter` instead, then `col` will be a reference,
        // and the borrow-checker is happy.
        let col_minmax: Vec<MinMaxResult<&u64>> = input_tranpose
            .par_iter()   
            .map(|col| col.iter().minmax())
            .collect();

        let rmm_ref = &row_minmax;
        let cmm_ref = &col_minmax;
        (0_usize..num_rows)
            .flat_map(|row_index| {
                (0_usize..num_cols).filter_map(move |col_index| {
                    match (rmm_ref[row_index], cmm_ref[col_index]) {
                        (MinMax(a, _b), MinMax(_c, d)) if a == d => 
                            Some((row_index, col_index)),
                        (MinMax(_a, b), MinMax(c, _d)) if b == c => 
                            Some((row_index, col_index)),
                        _ => None,
                    }
                })
            })
            .collect::<Vec<(usize, usize)>>()
    }
}

fn main(){}