How do I collect into an array?

I want to call .map() on an array of enums:

enum Foo {
    Value(i32),
    Nothing,
}

fn main() {
    let bar = [1, 2, 3];
    let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
}

but the compiler complains:

error[E0277]: the trait bound `[Foo; 3]: std::iter::FromIterator<Foo>` is not satisfied
 --> src/main.rs:8:51
  |
8 |     let foos = bar.iter().map(|x| Foo::Value(*x)).collect::<[Foo; 3]>();
  |                                                   ^^^^^^^ a collection of type `[Foo; 3]` cannot be built from an iterator over elements of type `Foo`
  |
  = help: the trait `std::iter::FromIterator<Foo>` is not implemented for `[Foo; 3]`

How do I do this?


The issue is actually in collect, not in map.

In order to be able to collect the results of an iteration into a container, this container should implement FromIterator.

[T; n] does not implement FromIterator because it cannot do so generally: to produce a [T; n] you need to provide n elements exactly, however when using FromIterator you make no guarantee about the number of elements that will be fed into your type.

There is also the difficulty that you would not know, without supplementary data, which index of the array you should be feeding now (and whether it's empty or full), etc... this could be addressed by using enumerate after map (essentially feeding the index), but then you would still have the issue of deciding what to do if not enough or too many elements are supplied.

Therefore, not only at the moment one cannot implement FromIterator on a fixed-size array; but even in the future it seems like a long shot.


So, now what to do? There are several possibilities:

  • inline the transformation at call site: [Value(1), Value(2), Value(3)], possibly with the help of a macro
  • collect into a different (growable) container, such as Vec<Foo>
  • ...

While you cannot directly collect into an array for the reasons stated by the other answers, that doesn't mean that you can't collect into a data structure backed by an array, like an ArrayVec:

use arrayvec::ArrayVec; // 0.7.0
use std::array;

enum Foo {
    Value(i32),
    Nothing,
}

fn main() {
    let bar = [1, 2, 3];
    let foos: ArrayVec<_, 3> = array::IntoIter::new(bar).map(Foo::Value).collect();
    let the_array = foos
        .into_inner()
        .unwrap_or_else(|_| panic!("Array was not completely filled"));
    // use `.expect` instead if your type implements `Debug`
}

Pulling the array out of the ArrayVec returns a Result to deal with the case where there weren't enough items to fill it; the case that was discussed in the other answers.