我正在try 实现一个函数,它将在几个相关的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)
            }
        )
    }

为了弄清楚到底是怎么回事,我最终try 用下面的代码替换它:

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

适用于两个版本.我看不出返回一个常量而不做任何其他事情的闭包怎么可能改变它的环境状态.我错过了什么吗?

推荐答案

我不知道为什么会发生这种情况,但如果您将闭包作为自己的变量,它在两种情况下都有效.

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以完全避免这种情况.这是首选,因为如果您想在以后对此进行优化,您可以在不 destruct 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(|| {})
}

Rust相关问答推荐

即使参数和结果具有相同类型,fn的TypId也会不同

空字符串转换为Box字符串时是否分配?<>

将已知大小的切片合并成一个数组,

如何对字符串引用的引用向量进行排序,而不是对最外层的引用进行排序?

如何处理动态 struct 实例化?

如何提高自定义迭代器的`extend`性能

如果包名称与bin名称相同,并且main.ars位于工作区的同一 crate 中,则无法添加对lib.ars的依赖

在0..1之间将U64转换为F64

当发送方分配给静态时,Tokio MPSC关闭通道

类型生命周期绑定的目的是什么?

Windows 上 ndarray-linalg 与 mkl-stats 的链接时间错误

为什么在 Allocator API 中 allocate() 使用 `[u8]` 而 deallocate 使用 `u8` ?

borrow 匹配手臂内部的可变

如何将这些测试放在一个单独的文件中?

LinkedList::drain_filter::drop 中 DropGuard 的作用是什么?

为什么指定生命周期让我返回一个引用?

`use std::error::Error` 声明中断编译

实现不消费的迭代器

如何为返回正确类型的枚举实现 get 方法?

如何为枚举中的单个或多个值返回迭代器