如何在嵌套映射中使用闭包?

Gys*_*cos 12 closures rust

我试图从创建每个元素的仿函数创建一个二维矩阵,并将其存储为一个平面Vec(每行连接).

我使用嵌套map(实际上是a flat_map和嵌套map)来创建每一行并连接它.这是我尝试过的:

fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T>
where
    F: Fn(usize, usize) -> T,
{
    (0..m).flat_map(|y| (0..n).map(|x| f(x, y))).collect()
}

fn main() {
    let v = make(5, 5, |x, y| x + y);

    println!("{:?}", v);
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我在编译期间遇到错误:

error[E0597]: `y` does not live long enough
 --> src/main.rs:5:45
  |
5 |     (0..m).flat_map(|y| (0..n).map(|x| f(x, y))).collect()
  |                                    ---      ^ -          - borrowed value needs to live until here
  |                                    |        | |
  |                                    |        | borrowed value only lives until here
  |                                    |        borrowed value does not live long enough
  |                                    capture occurs here
Run Code Online (Sandbox Code Playgroud)

如何在嵌套映射中使用闭包?我通过使用单个地图0..n*m解决了这个问题,但我仍然对答案感兴趣.

Lev*_*ans 8

在你的情况下,内部闭包|x| f(x,y)是一个借用闭包,它通过引用获取其环境(yf).

方式.flat_map(..)有效,它禁止您保留引用y,而不是来自外部范围.因此,我们需要让您的闭包按值获取其环境,这不是一个问题,y因为usize它是Copy:

(0..m).flat_map(|y| (0..n).map(move |x| f(x, y))).collect()
Run Code Online (Sandbox Code Playgroud)

但是,现在又出现了另一个问题:

error[E0507]: cannot move out of captured outer variable in an `FnMut` closure
 --> src/main.rs:5:36
  |
1 | fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T>
  |                                   - captured outer variable
...
5 |     (0..m).flat_map(|y| (0..n).map(move |x| f(x,y))).collect()
  |                                    ^^^^^^^^ cannot move out of captured outer variable in an `FnMut` closure
Run Code Online (Sandbox Code Playgroud)

在这里,我们试图移动f到闭包,这绝对是不可能的(除非m1,但编译器无法知道).

既然f是a Fn(usize, usize) -> T,我们也可以明确地传递&对它的引用,&引用是Copy:

fn make<T, F>(n: usize, m: usize, f: F) -> Vec<T>
where
    F: Fn(usize, usize) -> T,
{
    let f_ref = &f;
    (0..m)
        .flat_map(|y| (0..n).map(move |x| f_ref(x, y)))
        .collect()
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,闭包是按价值来看待它的环境,而这个环境是由yf_ref它们组成的Copy,一切都很好.

  • 你也可以写"fn make <T,F>(n:usize,m:usize,ref f:F) - > Vec <T>"来引用闭包. (2认同)