57

I'm attempting to simply convert a slice to a vector. The following code:

let a = &[0u8];
let b: Vec<u8> = a.iter().collect();

fails with the following error message:

3 |     let b: Vec<u8> = a.iter().collect();
  |                               ^^^^^^^ a collection of type `std::vec::Vec<u8>` cannot be built from an iterator over elements of type `&u8`

What am I missing?

  • `u8` != `&u8`. Possible duplicate of https://stackoverflow.com/questions/24689463/collect-into-owned-vec-of-owned-strings-in-rust, but the syntax changed a little bit since then. – Stefan Dec 26 '17 at 14:46
  • @Stefan What does `u8` have to do with strings? –  Dec 26 '17 at 14:55
  • let a = &[0u8]; let b: Vec<&u8> = a.iter().collect(); @Roxy , I tried this and it does work for me. If we make the genric as &u8 for b:Vec. – Ranjith Raj D Dec 26 '17 at 15:25

3 Answers3

99

Collecting into a Vec is so common that slices have a method to_vec that does exactly this:

let b = a.to_vec();

You get the same thing as CodesInChaos's answer, but more concisely.

Notice that to_vec requires T: Clone. To get a Vec<T> out of a &[T] you have to be able to get an owned T out of a non-owning &T, which is what Clone does.

Slices also implement ToOwned, so you can use to_owned instead of to_vec if you want to be generic over different types of non-owning container. If your code only works with slices, prefer to_vec instead.

trent
  • 25,033
  • 7
  • 51
  • 90
  • I actually needed to do something more complicated and unfortunately `to_vec` didn't work. The error I get is: `error[E0599]: no method named to_vec found for type std::iter::Take>> in the current scope` –  Dec 27 '17 at 21:15
  • 1
    @Roxy That's a different question: "how do I convert an iterator to a `Vec`?" `.collect()` is definitely the right answer to that one. – trent Dec 28 '17 at 01:16
19

The iterator only returns references to the elements (here &u8). To get owned values (here u8), you can used .cloned().

let a: &[u8] = &[0u8];
let b: Vec<u8> = a.iter().cloned().collect();
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
0

The clearest way to write this is simply

let b = Vec::from(a);

which makes it clear you are constructing a Vec object (the name of the type is there on the same line) using a from style constructor. (Again, the existence of the constructor function call makes this clear.)

Using to_vec is almost as clear but I suppose to_vec could be a random function in scope to do almost anything, and it doesn't contain the type name Vec.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • Well, if it is on slices, it is definitely this `to_vec()`. And if this is somewhen changed to another type, well, if someone creates a method named `to_vec()` that doesn't returns a `Vec`... Well, I suppose this is a _very bad_ design. – Chayim Friedman May 27 '23 at 18:21
  • @ChayimFriedman I agree that it would be bad design if to_vec would return something else. But that aside, this answer is clear and provides an answer that works for arrays as well as slices. Using the actual Vec type removes any doubt. Looks very elegant to me. – GolezTrol Jun 28 '23 at 19:33
  • @GolezTrol The `to_vec()` function is there so that people will use it. This is the most idiomatic solution, otherwise this function wouldn't exist. – Chayim Friedman Jun 29 '23 at 07:00
  • You can say exactly the same for `from`, right? There are two ways to do it. What makes one of them wrong? – GolezTrol Jun 29 '23 at 11:36
  • @GolezTrol No, the same argument doesn't apply to `from()`, for a very simple reason: `to_vec()` is an inherent method. It can only be called directly. Therefore, it is _meant_ to be called directly. On the other hand, `from()` (and `to_owned()`) are trait implementations, and are useful whenever something takes `impl Into`, even if they are not used directly. – Chayim Friedman Jun 29 '23 at 11:39
  • I used to take the view that `from` was a constructor function. I now take the view it is more of a general conversion function. If viewed as a constructor, it makes little sense to construct a complex type "from" a String. However, as a general conversion function, it does make sense to transmute "from" a String to some more complex type. `to_vec` suggests your type knows how to convert itself into a Vec, which is rarely a sensible thing for a type to do, unless it is strongly coupled with the Vec type itself. (Hence slices can call `to_vec`) – FreelanceConsultant Jun 30 '23 at 09:41
  • If you had a `Matrix` type, then it might make sense to have a `to_vec` for example. – FreelanceConsultant Jun 30 '23 at 09:42