rust 为什么这个闭包没有实现Fn?

omvjsjqw  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(108)

我正在尝试实现一个函数,它将为几个相关的2D数组(总是具有相同的大小)在整个可能的索引范围内构造迭代器。然而,编译器给了我一个错误,说我传递给map的闭包没有实现Fn,只有FnMut。这是我的原始代码:

pub fn get_index_iterator(&self) -> Map<Range<usize>, impl Fn(usize) -> (usize, usize)> {
        (0usize..(self.width * self.height))
            .map(|idx| -> (usize, usize) {
                (idx % self.width, idx / self.width)
            }
        )
    }

字符串
为了弄清楚发生了什么,我最终尝试用下面的代码替换它:

pub fn get_index_iterator(&self) -> Map<Range<usize>, impl Fn(usize) -> (usize, usize)> {
        (0usize..(self.width * self.height))
            .map(|idx| -> (usize, usize) {
                (0usize, 0usize)
            }
        )
    }


只是想看看错误是否会更改为更有用的内容,但它没有更改,错误仍然存在

expected a `std::ops::Fn<(usize,)>` closure, found `[closure@src\lib.rs:33:18: 33:41]`
the trait `std::ops::Fn<(usize,)>` is not implemented for closure `[closure@src\lib.rs:33:18: 33:41]`
`[closure@src\lib.rs:33:18: 33:41]` implements `FnMut`, but it must implement `Fn`, which is more general


对于这两个版本。我不明白一个返回常量而不做任何其他事情的闭包怎么可能改变它的环境状态。我错过了什么?

ezykj2lf

ezykj2lf1#

我不知道为什么会发生这种情况,但是如果你让闭包成为它自己的变量,它在两种情况下都能工作。

pub fn get_index_iterator(&self) -> Map<Range<usize>, impl Fn(usize) -> (usize, usize) + '_> {
    let f = |idx| -> (usize, usize) { (idx % self.width, idx / self.width) };
    (0usize..(self.width * self.height)).map(f)
}

字符串
您需要+ '_,因为它捕获了self,但它仍然是一个Fn,因为它应该是。因此,您正确地认为此闭包应该作为Fn工作。可能是map以某种方式降低了闭包的级别,但我不知道如何将其作为变量传递。
除此之外,您还可以将其写成impl Iterator,以完全避免这种情况。这是最好的选择,因为如果您希望稍后对其进行优化,则可以更改迭代器类型,而不会破坏API。它也更短。无论如何,您都需要mut来调用Map上的next,因此使用闭包Fn而不是FnMut不会带来任何好处。

pub fn get_index_iterator(&self) -> impl Iterator<Item = (usize, usize)> + '_


下面是一个显示相同行为的较短版本。

fn map<F: FnMut()>(f: F) -> F {
    f
}

pub fn returns_map() -> impl Fn() {
    // let c = || {};
    // map(c)
    map(|| {})
}

相关问题