【问题标题】:How to use closures in a nested map?如何在嵌套地图中使用闭包?
【发布时间】:2023-03-28 00:21:01
【问题描述】:

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

我使用嵌套的map(实际上是flat_map 和嵌套的map)来创建每一行并将其连接起来。 Here is what I tried:

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);
}

很遗憾,我在编译过程中遇到错误:

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

如何在嵌套映射中使用闭包?我解决了这个问题by using a single map on 0..n*m,但我仍然对答案感兴趣。

【问题讨论】:

  • 我希望由于 y:usize 是可复制的,它可以被内部闭包按值获取,从而避免任何借用...
  • 我同意,而且我有点惊讶这里有一个错误——我觉得这与FnMut 有关。也可能存在一个真正的错误,因为在所有变量上喷洒.clone() 并不能像我想的那样解决问题。

标签: closures rust


【解决方案1】:

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

.flat_map(..) 的工作方式禁止您保留对y 的引用,这不是来自外部范围。因此,我们需要让您的闭包按值获取其环境,这对于 yusize (即 Copy)来说不是问题:

(0..m).flat_map(|y| (0..n).map(move |x| f(x, y))).collect()

然而,现在又出现了一个问题:

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

在这里,我们试图将f 也移动到闭包中,这绝对是不可能的(除非m1,但编译器不知道这一点)。

由于fFn(usize, usize) -&gt; T,我们也可以显式传递&amp; 引用,而&amp; 引用是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()
}

在这种情况下,闭包通过值获取它的环境,而这个环境由yf_ref组成,它们都是Copy,一切都很好。

【讨论】:

  • 你也可以写 "fn make(n: usize, m: usize, ref f: F) -> Vec" 来引用闭包。
  • 完美!我对第二个错误感到困惑,我没有意识到它在谈论 f... @A.B.:很好!我总是忘记函数参数中的模式。
【解决方案2】:

添加到Levans's excellent answer,定义函数的另一种方式是

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

由于我们知道|x, y| x + yCopy 类型,f 将在flat_map 调用的每个回调中被复制。我仍然更喜欢 Levans 的方式,因为这不如复制参考文献有效。

【讨论】:

    猜你喜欢
    • 2018-06-17
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2021-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多