Difference between using macro `vec!` and method `to_vec`

Sorry if this question has already been done before (as I guess it is quite basic), but surprisingly I have not found it. What is the difference between the following two statements, and when should I use either one?

let x = vec![1, 2, 3];
let y = [1, 2, 3].to_vec();

I would also like to ask, since for String there are both to_string and String::from, why for Vec there is just to_vec and not Vec::from.


You can always check the documentation for vec!, click the [src] link and look at the definition:

macro_rules! vec {
    ($elem:expr; $n:expr) => (
        $crate::vec::from_elem($elem, $n)
    ($($x:expr),*) => (
        <[_]>::into_vec(box [$($x),*])
    ($($x:expr,)*) => (vec![$($x),*])

So vec! uses <[_]>::into_vec, not <[_]>::to_vec. If you look at the signatures, to_vec requires T: Clone, so into_vec is strictly more broadly useful.

Use whichever one you want. If one is faster, it's probably vec!, but unless you're constructing huge vectors as literals it probably won't matter much.

As for your assertion that there's no Vec::from: there's eleven of them, including one for slices.

1 Like

Oh, I hadn't noticed the into_vec part in the vec! definition, now I see the difference between vec! and to_vec. However, what is the reason for having to_vec silently cloning? Wouldn't it be better to have to_vec behave like to_string, and then have the user explicitly cloning only when necessary? This way vec! wouldn't even be needed, correct?

Regarding Vec::from could you please provide an example on how to use it to convert an array or slice into a Vec? (I'm not sure what I'm doing wrong here...)

Thanks again

I don't follow the question. to_string allocates a new String.

I corrected my last message to remove the allocation part which was obviously wrong. However, looking at the signatures of to_vec and to_string I understand that the former implicitly clones, while the latter doesn't, is it correct?

pub fn to_vec(&self) -> Vec<T>
    T: Clone,`
fn to_string(&self) -> String

The description says for to_vec "Copies self into a new Vec" and for to_string "Converts the given value to a String", which is similar to into_vec's description "Converts self into a vector without clones or allocation". So do I understand correctly that to_string behaves similarly to into_vec, while to_vec behaves differently? (by cloning)

Sorry for my questions, but I'm coming back to Rust after many years of not using it, and I feel a little rusty...

to_string has a different description, but, for <&str>::to_string at least, it's doing the same operation. <&[u32]>::to_vec clones each u32 and allocates a new Vec to hold the cloned values. <&str>::to_string clones each u8 holding the string data inside the string and allocates a new String to hold the cloned values.

Note that as both of these are "to" operations, the original data is still usable after doing things.

into_vec is different because it doesn't operate on &[u32], but rather Box<[u32]>- something already allocated on the heap. It's an "into" operation because it is completely consuming the Box<[u32]> and transforming it into a Vec<u32>. It isn't doing any allocation, but at the same time the original Box<[u32]> is not usable.

The description for to_string is such because it's also usable for types other than &str. But in all cases it creates a new string and does not consume the original value. This is why it's a "to" operation not an "into" operation.

to_string comes from the ToString trait: ToString in std::string - Rust

Where you can see that its blanket implementation (the one you'll usually be using) is in terms of the Display trait: Display in std::fmt - Rust

So x.to_string() is almost always just format!("{}", x), and thus rather different from something doing cloning.

It's different from cloning, but it is still more similar to to_vec than into_vec, just because both to_string and to_vec are "to" operations and allow someone to continue using the original data.

Thanks for your answers, now it's clearer to me.

Can you please provide an example on how to use Vec::from to convert an array or slice into a Vec?

Also I would like to ask if there is the equivalent of vec! for String (something to create a String consuming the original &str).

let s: &[&str] = &["a", "b"];
let v = Vec::from(s);

What do you mean by consuming the original? Since it’s a borrow you wouldn’t consume it, at least in how the term "consume" is typically used.

There are many ways to create a String - are you only interested in a &str case?

Following your example, I now see that for instance the following code works:

let s: &[_] = &[1, 2];
let v = Vec::from(s);

What I attempted before was:

let s = &[1, 2];
let v = Vec::from(s);

Can you please explain why this one instead does not work? Doesn't Rust infer the same type &[T] for variable s in both cases?

As for my second question, if I understand correctly with into_vec the original vector is moved, so it is consumed by into_vec, meaning that it is not available anymore afterwards (I hope I'm expressing myself correctly). In other words, after calling into_vec there is only one memory region allocated to store the Vec. I wonder why there are no equivalent str! macro and into_string method to convert a &str into a String while consuming the original &str.

The type there becomes &[i32;2], a reference to a 2 element array. It doesn’t coerce it to a slice unless that’s what you ask for (or you use the array in a place where automatic deref coercion takes place).

into_vec consumes a Box<[T]>, not a Vec. You’re right that no extra allocations or copies are done here; this is accomplished by having the Vec take ownership of the heap allocation that the Box had already done.

&str doesn’t own the allocation, unlike a Box, so there’s nothing to consume; you can copy the content into a new String, but original is left intact and owned by someone else. The analogous to the above is str - Rust.