HashMap from array of tuples problem

(This comes from AoC) Could someone tell me why this compiles:

let instructions: &[(_, fn(r: &mut [usize], a: usize, b: usize) -> usize)] = &[
    ("addr", |r, a, b| r[a] + r[b]),
    ("addi", |r, a, b| r[a] + b),
    ("mulr", |r, a, b| r[a] * r[b]),
    ("muli", |r, a, b| r[a] * b),
    ("banr", |r, a, b| r[a] & r[b]),
    ("bani", |r, a, b| r[a] & b),
    ("borr", |r, a, b| r[a] | r[b]),
    ("bori", |r, a, b| r[a] | b),
    ("setr", |r, a, _| r[a]),
    ("seti", |_, a, _| a),
    ("gtir", |r, a, b| (a > r[b]).into()),
    ("gtri", |r, a, b| (r[a] > b).into()),
    ("gtrr", |r, a, b| (r[a] > r[b]).into()),
    ("eqir", |r, a, b| (a == r[b]).into()),
    ("eqri", |r, a, b| (r[a] == b).into()),
    ("eqrr", |r, a, b| (r[a] == r[b]).into())];

let instructions: HashMap<_, _> = instructions.iter().cloned().collect();

And this doesn't?

let instructions2: HashMap<&str, fn(r: &mut [usize], a: usize, b: usize) -> usize> = [
    ("addr", |r, a, b| r[a] + r[b]),
    ("addi", |r, a, b| r[a] + b),
    ("mulr", |r, a, b| r[a] * r[b]),
    ("muli", |r, a, b| r[a] * b),
    ("banr", |r, a, b| r[a] & r[b]),
    ("bani", |r, a, b| r[a] & b),
    ("borr", |r, a, b| r[a] | r[b]),
    ("bori", |r, a, b| r[a] | b),
    ("setr", |r, a, _| r[a]),
    ("seti", |_, a, _| a),
    ("gtir", |r, a, b| (a > r[b]).into()),
    ("gtri", |r, a, b| (r[a] > b).into()),
    ("gtrr", |r, a, b| (r[a] > r[b]).into()),
    ("eqir", |r, a, b| (a == r[b]).into()),
    ("eqri", |r, a, b| (r[a] == b).into()),
    ("eqrr", |r, a, b| (r[a] == r[b]).into())]
    .iter().cloned().collect();

The second gives the errors:

error[E0282]: type annotations needed
--> ...\test.rs:26:19
|
26 | ("addr", |r, a, b| r[a] + r[b]),
| ^ consider giving this closure parameter a type
|
= note: type must be known at this point

error[E0277]: a collection of type std::collections::HashMap<&str, for<'r> fn(&'r mut [usize], usize, usize) -> usize> cannot be built from an iterator over elements of type (&str, [closure@...\test.rs:35:18: 35:29])
--> ...\test.rs:42:26
|
42 | .iter().cloned().collect();
| ^^^^^^^ a collection of type std::collections::HashMap<&str, for<'r> fn(&'r mut [usize], usize, usize) -> usize> cannot be built from std::iter::Iterator<Item=(&str, [closure@...\test.rs:35:18: 35:29])>
|
= help: the trait std::iter::FromIterator<(&str, [closure@...\test.rs:35:18: 35:29])> is not implemented for std::collections::HashMap<&str, for<'r> fn(&'r mut [usize], usize, usize) -> usize>

Because Rust can't infer the types of the closures with that much indirection.

2 Likes