Expected Fn / fn, found [closure@...]

I want to store some closures in a HashMap. I'm sure these closures will not capture anything. I tried two methods, shown in the following example:

use std::collections::HashMap;

enum A {
    B,
    C,
}

fn donotwork() {
    let g: HashMap<u8, fn(A) -> A> = HashMap::from([(0, |x: A| x)]);
    let h: HashMap<u8, Box<dyn (Fn(A) -> A) + Sync>> = HashMap::from([(0, Box::new(|x: A| x))]);
}

(Playground link here)

(I used HashMap just to make sure the environment here is similar enough to the real scenario. The Fn can be replaced by FnOnce and FnMut, with similar results.)

Both won't compile.

error[E0308]: mismatched types
 --> src/lib.rs:9:38
  |
9 |     let g: HashMap<u8, fn(A) -> A> = HashMap::from([(0, |x: A| x)]);
  |            -----------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `HashMap<u8, fn(A) -> A>`, found `HashMap<{integer}, ...>`
  |            |
  |            expected due to this
  |
  = note: expected struct `HashMap<u8, fn(A) -> A>`
             found struct `HashMap<{integer}, [closure@src/lib.rs:9:57: 9:63]>`

error[E0308]: mismatched types
  --> src/lib.rs:10:56
   |
10 |     let h: HashMap<u8, Box<dyn (Fn(A) -> A) + Sync>> = HashMap::from([(0, Box::new(|x: A| x))]);
   |            -----------------------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `HashMap<u8, Box<...>>`, found `HashMap<{integer}, Box<...>>`
   |            |
   |            expected due to this
   |
   = note: expected struct `HashMap<u8, Box<dyn Fn(A) -> A + Sync>>`
              found struct `HashMap<{integer}, Box<[closure@src/lib.rs:10:84: 10:90]>>`

I don't understand what these error mean. Doesn't closures implement the Fn trait? Why is the closure with (strange) type [closure@...]? How can I fix the issue?

Thanks.

You need to nudge type inference a little here:

use std::collections::HashMap;

enum A {
    B,
    C,
}

fn donotwork() {
    let g: HashMap<u8, fn(A) -> A> = HashMap::from([(0u8, (|x: A| x) as _)]);
    let h: HashMap<u8, Box<dyn (Fn(A) -> A) + Sync>> = HashMap::from([(0, Box::new(|x: A| x) as _)]);
}

Playground.

See i.e. this topic for a similar issue I encountered when using collections with elements that need to be coerced:

or this topic:


BTW, I created a macro that makes it easy for you to create a hashmap with values that need to be coerced to a different type before you can store them: map_macro::hash_map_e :smile:. It uses the same trick with explicit coercion to "something" (the _ placeholder) under the hood.

3 Likes

Thank you for your quick respond! That solves my problem.

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.