Closures of the same type can be stored in an array, why can't they be stored in a Vec?

playground link

Compile Error:

error[E0308]: mismatched types
 --> src/
4 |     let closures_1 = || {};
  |                      ----- the expected closure
7 |     let v2 = vec![closures_1, closures_2,]; // ❌
  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice, found array of 2 elements
  = note: expected struct `Box<[[closure@src/ 4:27]], _>`
             found struct `Box<[fn(); 2], std::alloc::Global>`
  = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)

why is that?

Neither of the closures captures an environment, so they coerce to the function pointer type fn(). (If one or both of them had captures then neither example would compile.) It looks like something in the expansion of the vec macro is blocking that coercion. If you cast explicitly like vec![closures_1 as fn(), closures_2 as fn()] there's no error.

Edit: experimenting with manually expanding vec!, it looks like the coercion is blocked by box expressions: this compiles

fn main() {
    let f = || {};
    let g = || {};
    let v = <[_]>::into_vec(Box::new([f, g]));

but this doesn't (nightly-only)

fn main() {
    let f = || {};
    let g = || {};
    let v = <[_]>::into_vec(box [f, g]);

I guess x in box x isn't a coercion site?

1 Like

I think this is #22405 / the downside listed in RFC 809, but didn't spend too much time digging.

Not sure if it's more desirable to keep the presumed optimization or to make the stdlib stop "cheating" in this case (by exploiting capabilities no longer expected to be made stable in their currrent form).


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.