函数式 Rust:为什么要在闭包中借用“filter”?

gbe*_*rth 3 functional-programming rust

我正在尝试练习使用 Rust 的函数功能。

例如,我想转换这个循环:

levels: Vec<Vec<u8>> = //< Built by something

let mut total = 0;
for (x, y) in iproduct!(0..10, 0..10) {
    if levels[x][y] > 9 {
        total += count_something(levels, x, y);
    }
}

// Edit: here's the `count_something` function signature
fn count_something (levels: &mut Vec<Vec<u8>>, x: usize, y: usize) -> usize {
    // Count
}
Run Code Online (Sandbox Code Playgroud)

这是我的功能重构的结果:

iproduct!(0..10, 0..10)
    .filter(|(x, y)| levels[*x][*y] > 9)
    .map(|(x, y)| count_something(levels, x, y))
    .sum()
Run Code Online (Sandbox Code Playgroud)

问题是:这段代码无法编译。
错误:error[E0500]: closure requires unique access to *levels but it is already borrowed

我不明白为什么filter要借用levels二维矩阵。
我对幕后发生的事情的心理模型似乎不够充分。

Mas*_*inn 7

我不明白为什么过滤器借用了级别二维矩阵。我对幕后发生的事情的心理模型似乎不够充分。

filter的回调需要访问矩阵,所以这里有一个借用(替代方案是移动):在 Rust 中,闭包是结构 + 可调用的语法糖,任何自由变量都会自动转换为隐式成员,匿名结构:

.filter(|(x, y)| levels[*x][*y] > 9)
Run Code Online (Sandbox Code Playgroud)

变成(或多或少,有很多被跳过)

struct $SECRET1$ {
    levels: &Vec<Vec<u8>>
}
impl $SECRET1$ {
    fn call(&self, x: &usize, y: &usize) -> bool {
        self.levels[*x][*y] > 9
    }
}
[...]
.filter($SECRET1$ { levels: &levels })
Run Code Online (Sandbox Code Playgroud)

所以这就是levels借钱的原因。

问题的另一部分是为什么在映射运行时仍然借用级别,答案是 Rust 的迭代器是惰性的,因此它们同时(交错)运行操作,而不是顺序运行。

因此当你写

iproduct!(0..10, 0..10)
    .filter(|(x, y)| levels[*x][*y] > 9)
    .map(|(x, y)| count_something(levels, x, y))
    .sum()
Run Code Online (Sandbox Code Playgroud)

你真的在写这样的东西:

let p = iproduct!(0..10, 0..10);
let f = Filter {
    f: |(x, y)| levels[*x][*y] > 9,
    iter: p
};
let m = Map {
    f: |(x, y)| count_something(levels, x, y),
    iter: f
};
Iterator::sum(m)
Run Code Online (Sandbox Code Playgroud)

因此,正如您可以看到Map.fFilter.f同时存在并且需要相同的数据一样,如果两者都只需要从中读取数据就可以了,但显然count_something(因此map)需要一个可变(唯一)引用,并且这与只读(共享)引用。