Confusing behavior of `into_iter` on vector and array

As the screenshot below shows, the following code block works

let words = vec!["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);

however, it doesn't work if array is used.

let words = ["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);

It seems to me that words.into_iter() generates an iterator of &&str (instead of &str). Can anyone explain the reason behind this?

Please post your code as text rather than an image.

IntoIterator for arrays are only implemented for slices. You can only return references from a slice.

You can do this if you want to own the iterated items:

fn main() {
    let words = ["alpha", "beta", "gamma"];
    let merged: String = words.iter().cloned().collect();
    println!("{}", merged);
}

Alternatively, there is an owned array iterator API: std::array::IntoIter - Rust. (Or see this issue to see some more recent discussion of the status of this.)

So what actually happens on calling words.into_iter() is that method resolution will look for a type that implements IntoIterator (the trait that into_iter() belongs to). In particular, method resolution can do some auto-referencing, which means it will check [&str; 3] then &[&str; 3] and then &mut [&str; 3] for IntoIterator implementations. The first one that implements it is &[&str; 3] with an Item type &&str. (Generically &[T; N] turns into an iterator with item type &T). There is, as @skysch already mentioned, some newer work on providing an IntoIterator implementation for [T; N], too (already on nightly). This will eventually change the behavior of your words.into_iter() call to make the situation more similar to the Vec.

One reason why it took a while to get such an implementation is that it involces const generics (std::array::IntoIter has a N: usize parameter). Also since this change has the potential of breaking lots of existing code, there’s been work to special-case method resolution so that your words.into_iter() example might actually only change in the upcoming Rust 2021 edition.

1 Like