Why pass reference to closure instead of value?

The following code is an example solution of one Exercism exercise:

use std::collections::HashMap;
pub fn can_construct_note(magazine: &[&str], note: &[&str]) -> bool {
    let magazine_words = magazine.iter().fold(HashMap::new(), |mut words, str| {
        *words.entry(str).or_insert(0) += 1;
        words
    });
    let note_words = note.iter().fold(HashMap::new(), |mut words, str| {
        *words.entry(str).or_insert(0) += 1;
        words
    });
    note_words
        .iter()
        // why???
        .all(&|(w, count)| magazine_words.get(w).unwrap_or(&0) >= count)
}

  • First question, as the title suggests, what's the point of doing that? Since we're going to consume the closure only once anyway in this case. Is that a Rust convention or idiom that I missed?

  • Second question, why is this code valid? Since Iterator::all() takes F as second argument, not &F. Iterator in std::iter - Rust

pub fn all<F>(&mut self, f: F) -> bool
where
    Self: Sized,
    F: FnMut<(Self::Item,), Output = bool>,

A type parameter F means "any type". It does not exclude reference types. Rust doesn't really treat any types specially in the context of generics (which is the whole point of generics). Types can be primitives, structs, enums, references, arrays, raw pointers, etc., whatever satisfies the declared trait bounds.

4 Likes

Regarding why, I suspect that this particular instance is a typo: maybe they intended to use & inside the closure args to perform some more advanced "pattern-match destructuring"?


That being said, out there in the wild, there can be instances where prefixing a closure with &mut (or &) can be useful, when dealing with a dyn Fn… API (polymorphic not through generics, but through dynamic dispatch (~"dynamic types")):

/// A function such as this one will often be written as:
/// `fn example (mut f: impl FnMut())` instead, but if this function
/// were a trait method instead, then in order for that trait
/// to be `dyn`-safe, `impl` / generics would not be available,
/// making this `&mut dyn` API mandatory.
fn example (f: &mut dyn FnMut())
{
    f();
}

// To call `example`:

example(&mut || {
    // …
});
1 Like

Right. F can be any type, including reference type, as long as it satisfies the trait bound. Also, I found this blog post which explains why:

I suspected that too but not so sure about it as a beginner :sweat_smile:. Thank's for your confirmation and extra info.

To add, here's the code in the standard library that provides this impl:

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, F: ?Sized> Fn<A> for &F
where
    F: Fn<A>,
{
    extern "rust-call" fn call(&self, args: A) -> F::Output {
        (**self).call(args)
    }
}
1 Like

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.