Generic higher-order function syntax

I've a books: &mut Vec<u32>. I want to pass to a function, such that, given a closure, the function either returns all the indices that have non-zero values, or the non-zero values.

For example:

books: [0, 1, 1]

will return [1, 2] for indices, and [1, 1] for values.

My attempt, that doesn't compile:

fn find_non_zero<T>(books: &[u32], f: fn(usize, &u32) -> T) -> T {
        .filter(|(_, &count)| count > 0)

Call it for values: find_non_zero(books, |(_, &count)| count)
Call it for indices: find_non_zero(books, |(b, _)| b)

What is the correct syntax for this?

Like this?

Why fn(usize, &u32) -> T doesn't work, but FnMut((usize, &u32)) -> T does?

I realize have a typo there, the fn signature I'd shown doesn't accept a tuple, but in my code it does. I missed a ().

This compiles and does what I think you were asking for:

fn find_non_zero<'a, T: 'a>(
    books: &'a [u32],
    f: fn((usize, &u32)) -> T,
) -> impl Iterator<Item = T> + 'a {
        .filter(|&(_, count)| *count > 0)

Most of the adjustments I had to make were to get the reference layers to work out, and the fact that map is expecting a function that accepts a single parameter of (usize, &u32) rather than two parameters.

You didn't specify what the output type should be, so I removed the collect() and returned an Iterator of whatever the provided function outputs. Because the iterator has to capture a reference to the original slice, this requires all the lifetime bounds. If you returned a Vec like in the other answer, it would not be necessary because the iterator wouldn't live longer than the call


Incidentally you can check the docs to see that map expects a FnMut(Self::Item) -> B (which only takes one argument).

If you want to allow multiple arguments (like your original bounds, but not like your original closures), you would need to do something like

// bind f as mutable and then
.map(|(b, c)| f(b, c)) // go from one argument (a 2-tuple) to two arguments

(There is no auto-splatting of tuples.)

From the previous replies, I recommend returning the iterator unless you have some reason not to, but using the FnMut bound (which will accept closures the fn function pointer version cannot, and avoid some indirection).

1 Like

Understood, and thanks, as always.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.