Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the iterator type returned by this Rust function?

So I have this example code here:

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)
}

I'm trying to return an iterator, which has always been pretty hairy in Rust from what I've gathered. Running the code here gives me this error:

<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)
              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now, working off this (and based on my relatively limited knowledge of how this all works), it seems I should do something like:

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

But now I'm stuck again, because I'm given [closure <anon>:13:27: 13:44] instead of an actual type. Even when I tried using the function here to try and find out the type, I was given:

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

So, trying to figure it out on my own, and basing it on the previous line, I attempted:

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

and got even more errors, because Fn is not constant at compile time (i.e. doesn't implement Sized). It makes sense, but I'm at a bit of a loss what else to try.

EDIT: I just tried:

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

and now I'm getting these errors:

<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)
                                    ^~~~~~~~~~~~~~~~~
like image 506
niconii Avatar asked Nov 01 '22 07:11

niconii


1 Answers

Each closure has its own unique type (closures are sugar for a struct and a Fn, FnMut or FnOnce implementation, as determined) and there is no way of writing out the type of a closure.

One thing you can do is write it as a function and then cast it to a function pointer, as shown below.

Another thing is using boxed functions (Box<Fn(&&i32) -> bool>), like Box::new(|&&n| n % 10 == 6). This involves a heap allocation and is in consequence not the most efficient, though in real life you don’t need to worry about the performance differences.

The generic attempt you made doesn’t work because generics are about allowing the caller to specify a type, any type, where in this case you want the callee to specify a single unique type.

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)
}
like image 171
Chris Morgan Avatar answered Dec 04 '22 10:12

Chris Morgan