这个 Rust 函数返回的迭代器类型是什么?

5

我这里有一个示例代码:

use std::iter::Filter;
use std::slice::Iter;

fn main() {
    let numbers = vec![12i32, 26, 31, 56, 33, 16, 81];

    for number in ends_in_six(numbers) {
        println!("{}", number);
    }
}

fn ends_in_six(numbers: Vec<i32>) /* -> ??? */ {
    numbers.iter().filter(|&n| *n % 10 == 6)
}

我试图返回一个迭代器,在Rust中这一直是一个棘手的问题。从我收集到的信息来看,运行这里的代码会给我带来以下错误:
<anon>:13:5: 13:45 error: mismatched types:
 expected `()`,
    found `core::iter::Filter<core::slice::Iter<'_, i32>, [closure <anon>:13:27: 13:44]>`
(expected (),
    found struct `core::iter::Filter`) [E0308]
<anon>:13     numbers.iter().filter(|&n| *n % 10 == 6)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

现在,在这个基础上工作(根据我相对有限的了解,这是所有工作的基础),似乎我应该做一些像这样的事情:

fn ends_in_six<'a>(numbers: Vec<i32>) -> Filter<Iter<'a, i32>, /* ??? */> {

现在我又遇到了麻烦,因为我得到的是 [closure <anon>:13:27: 13:44] 而不是实际类型。即使我尝试使用这里的函数来查找类型,我也得到了:

core::iter::Filter<core::slice::Iter<i32>, [closure((&&i32,)) -> bool]>

因此,我试图自己找出答案,并根据前一行尝试了以下内容:

fn ends_in_six<'a>(numbers: Vec<i32>) -> Filter<Iter<'a, i32>, Fn(&&i32) -> bool> {

我尝试了一下,并且收到更多错误,因为Fn在编译时不是常量(即不实现Sized)。这很有道理,但是我有点迷茫,不知道该尝试什么。

编辑:我刚刚尝试了

fn ends_in_six<'a, F>(numbers: Vec<i32>) -> Filter<Iter<'a, i32>, F>
  where F: Fn(&&i32) -> bool {

现在我遇到了以下错误:

<anon>:7:19: 7:30 error: unable to infer enough type information about `_`; type annotations required [E0282]
<anon>:7     for number in ends_in_six(numbers) {
                           ^~~~~~~~~~~
<anon>:14:32: 14:34 error: the type of this value must be known in this context
<anon>:14     numbers.iter().filter(|&n| *n % 10 == 6)
                                         ^~
<anon>:14:27: 14:44 error: mismatched types:
 expected `F`,
    found `[closure <anon>:14:27: 14:44]`
(expected type parameter,
    found closure) [E0308]
<anon>:14     numbers.iter().filter(|&n| *n % 10 == 6)
                                    ^~~~~~~~~~~~~~~~~

"我正在尝试返回一个迭代器,这通常非常棘手" - 难点并不在于返回一个迭代器,而是通常需要返回一个包含闭包的迭代器适配器,或者返回一个未具体化的类型,该类型实现了Iterator,其大小未知。 - Shepmaster
1
如果你不介意装箱,返回一个包含闭包的迭代器很容易:http://is.gd/nBad0O --- 一旦我们获得了impl Trait返回类型,摆脱装箱也很容易。 - user395760
1个回答

2
每个闭包都有自己独特的类型(闭包是一个结构体和FnFnMutFnOnce实现的语法糖),没有办法写出闭包的类型。
你可以将其编写为函数,然后将其强制转换为函数指针,如下所示。
另一种方法是使用带有堆分配的函数指针(Box<Fn(&&i32) -> bool>),例如Box::new(|&&n| n % 10 == 6)。这涉及到堆分配,并且因此不是最有效的,但在实际应用中,您不需要担心性能差异。
您尝试的通用方法无法工作,因为通用方法是允许调用者指定任何类型的方法,而在这种情况下,您想要被调用者指定单个唯一类型。
use std::iter::Filter;
use std::slice::Iter;

fn main() {
    let numbers = vec![12i32, 26, 31, 56, 33, 16, 81];

    for number in ends_in_six(numbers) {
        println!("{}", number);
    }
}

fn ends_in_six(numbers: Vec<i32>) Filter<Iter<'a, i32>, fn(&&i32) -> bool> {
    fn filterer(&&n: &&i32) -> bool { n % 10 == 6 }
    numbers.iter().filter(filterer as fn(&&i32) -> bool)
}

结尾的代码无法运行,即使我修复了微不足道的语法错误,“numbers”毫不意外地也无法长时间存在。最好使用“&[i32]”而不是“Vec<i32>”。 - user395760
这个解释很有帮助,再加上delnan的代码,解决了我的问题,所以谢谢。 - niconii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接