我可以根据闭包指定迭代器的类型吗?

yai*_*chu 6 closures types rust

我编写了一个函数来迭代二维网格中单元格的邻居:

pub fn neighbours(
    (width, height): (usize, usize),
    (x, y): (usize, usize),
) -> impl Iterator<Item = (usize, usize)> {
    [(-1, 0), (1, 0), (0, -1), (0, 1)]
        .iter()
        .map(move |(dx, dy)| (x as i64 + dx, y as i64 + dy))
        .filter(move |&(nx, ny)| 0 <= ny && ny < height as i64 && 0 <= nx && nx < width as i64)
        .map(|(nx, ny)| (nx as usize, ny as usize))
}
Run Code Online (Sandbox Code Playgroud)

请注意,它返回一个impl Iterator<Item = (usize, usize)>.

如果我理解正确,返回 animpl会导致代码变慢,调用函数指针而不是将内容编译为简单的循环。正确的?

因此,想要指定更精确的类型,我将类型替换为,()以查看编译器推断出的类型,并且它推断出

std::iter::Map<std::iter::Filter<std::iter::Map<std::slice::Iter<'l, (i64, i64)>, _>, _>, _>
Run Code Online (Sandbox Code Playgroud)

其中_s 代表闭包,我不知道如何指定它们的类型。

我尝试提取具有Fn特征的结构的闭包,但无法使其工作,而且IIUC 实现Fn特征是一个不稳定的功能,我不应该使用它

tre*_*tcl 4

\n

如果我理解正确,返回 animpl会导致代码变慢,调用函数指针而不是将内容编译为简单的循环。正确的?

\n
\n

没有。从代码生成角度来看,返回impl Iterator<Item = (usize, usize)>与返回 .\xc2\xb9 完全相同,Map<Filter<Map<...>>>区别有两个:

\n
    \n
  • 更改 的返回类型neighbours不需要更改其签名,因此impl Iterator与其返回类型的更改向前兼容。
  • \n
  • impl Iterator不会与其他不透明impl Iterator类型统一,即使它们碰巧具有相同的基础类型。(简单来说:编译器不允许您从不同来源创建 of Vecimpl Iterator即使所有这些不透明类型都是相同的具体类型。)
  • \n
\n

这些差异都不会影响代码生成或编译器内联任何内容的能力,因此请继续使用impl Iterator.

\n

在一种情况下,您仍然必须使用间接调度 ( dyn Iterator):当函数neighbours本身是特征的一部分时,impl Trait语法尚不可用(从 1.59 开始)。目前解决这个问题最好的办法就是返回Box<dyn Iterator>。(但是请注意,这并不意味着每个调用都会动态调度;对的调用.next()将会动态调度,但“内部”的所有内容仍然使用易于优化的静态调度。)

\n

相关问题

\n\n
\n

\xc2\xb9 请注意,为了实际返回 Map<Filter<Map<...>>>,您仍然必须使用impl Trait来表示闭包,因为它们具有匿名类型。

\n