将迭代器映射到矩阵的元素时的生命周期问题

时间:2014-11-16 07:23:59

标签: iterator rust lifetime

我的目标是检索矩阵中所有元素的迭代器以及与每个元素关联的行号。

以下是我遇到的终身问题的简化版本。

fn main() {

    let mat = [ [1i32, 2,    3],
                [4,    5,    6],
                [7,    8,    9] ];

    // Create an iterator that produces each element alongside its row number.
    let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| {
        arr.iter().map(|elem| (row, elem)) // Error occurs here.
    });

    for (row, elem) in all_elems {
        println!("Row: {}, Elem: {}", row, elem);
    }

}

这是我得到的错误:

<anon>:10:9: 10:43 error: cannot infer an appropriate lifetime for lifetime parameter 'r in function call due to conflicting requirements
<anon>:10         arr.iter().map(|elem| (row, elem))
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:10:24: 10:42 note: first, the lifetime cannot outlive the expression at 10:23...
<anon>:10         arr.iter().map(|elem| (row, elem))
                                 ^~~~~~~~~~~~~~~~~~
<anon>:10:24: 10:42 note: ...so type `|&i32| -> (uint, &i32)` of expression is valid during the expression
<anon>:10         arr.iter().map(|elem| (row, elem))
                                 ^~~~~~~~~~~~~~~~~~
<anon>:10:9: 10:43 note: but, the lifetime must be valid for the method call at 10:8...
<anon>:10         arr.iter().map(|elem| (row, elem))
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<anon>:10:24: 10:42 note: ...so that argument is valid for the call
<anon>:10         arr.iter().map(|elem| (row, elem))
                                 ^~~~~~~~~~~~~~~~~~

这是playpen link

问题似乎源于无法在map方法的闭包参数中推断生命周期,尽管我不确定为什么。

  • 有人可以更清楚地解释这个问题吗?
  • 是否有可能以另一种方式生成所需的迭代器?

2 个答案:

答案 0 :(得分:5)

即使不是很清楚,编译器也无法弄清楚内部闭包的生命周期

|elem| (row, elem)

因为这个闭包从它的环境中捕获row(这里它是你的外部闭包的主体),因此不应该比它活得更久。

然而,你试图将它包装回Map<>返回的.map(..)对象中,因此要求相互冲突:你的内部封闭被要求超过它可以超越的范围。 !

一个逃避这个问题的简单方法是让你的内部闭包也以row为参数,为此,我们可以使用:

  • repeat(..)创建一个永远重复同一项的迭代器
  • .zip(..)迭代器方法,允许同时前进两个迭代器

为了这样的方式:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| {
    arr.iter()
       .zip(repeat(row))
       .map(|(elem, my_row)| (my_row, elem))
});

但在这种情况下,我们可以使它变得更加简单,因为|(elem, my_row)| (my_row, elem)看起来很无用:

let mut all_elems = mat.iter().enumerate().flat_map(|(row, arr)| {
    repeat(row).zip(arr.iter())
});

答案 1 :(得分:2)

另一种增加内封闭|elem| (row, elem)生命周期的方法 只需添加move关键字即可将其标记为移动闭包。这也将编译:

let all_elems = mat.iter().enumerate().flat_map(|(row, arr)| {
    arr.iter().map(move |elem| (row, elem))
});

尝试从函数返回(盒装)闭包时也可以观察到相同的行为。以下函数无法编译,因为闭包的生命周期受局部变量row的生命周期约束:

fn foo_fail() -> Box<Fn(u32) -> (u32, u32)> {
    let row = 1;
    Box::new(|elem| (row, elem))
}

使用移动闭包可以正常工作:

fn foo_success() -> Box<Fn(u32) -> (u32, u32)> {
    let row = 1;
    Box::new(move |elem| (row, elem))
}