Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vector method push_all is not found for a custom struct

Tags:

rust

So in this simple example

#![feature(collections)]

struct User {
    reference: String,
    email: String
}

fn main() {

    let rows = vec![
        vec!["abcd".to_string(), "[email protected]".to_string()],
        vec!["efgh".to_string(), "[email protected]".to_string()],
        vec!["wfee".to_string(), "[email protected]".to_string()],
        vec!["rrgr".to_string(), "[email protected]".to_string()]
    ];
    let mut rows_mut: Vec<Vec<String>> = Vec::new();
    rows_mut.push_all(&rows);

    let mut users_mut: Vec<User> = Vec::new();
    let users = vec![
        User { reference: "ref1".to_string(), email: "[email protected]".to_string() },
        User { reference: "ref2".to_string(), email: "[email protected]".to_string() }
    ];
    users_mut.push_all(&users);

}

I'm getting an error

src/main.rs:24:12: 24:28 error: no method named `push_all` found for type `collections::vec::Vec<User>` in the current scope
src/main.rs:24  users_mut.push_all(&users);
                          ^~~~~~~~~~~~~~~~
error: aborting due to previous error

Why does it work for Vec<String>, but not for Vec<User>? Is the only way in this case to iterate and add elements one by one?

like image 935
Caballero Avatar asked Jun 16 '26 02:06

Caballero


2 Answers

Look at the definition of push_all:

impl<T> Vec<T> where T: Clone {
    fn push_all(&mut self, other: &[T]);
}

Appends all elements in a slice to the Vec.

Iterates over the slice other, clones each element, and then appends it to this Vec. The other vector is traversed in-order.

(Emphasis mine.)

Your type must implement Clone because it clones each value. String does; User doesn’t. You can add #[derive(Clone)] to it.

If you are willing to consume the source vector, you should use x.extend(y.into_iter()) which avoids needing to clone the values.

Of course, for this trivial case if it’s purely the difference in mutness, just add the mut in the initial pattern (if it’s a function argument this works too, the bit before the colon in each argument is a pattern, like with let, so fn foo(mut x: Vec<T>) { … } works fine and is equivalent to fn foo(x: Vec<T>) { let mut x = x; … }.)

like image 91
Chris Morgan Avatar answered Jun 18 '26 21:06

Chris Morgan


Because, if you go to the documentation for Vec::push_all and scroll up and little, you'll see this line:

impl<T: Clone> Vec<T>

This means that the following methods are only implemented for Vec<T> when T implements Clone. In this case, T would be User, and User does not implement Clone. Therefore, the method does not exist.

You can solve this by adding #[derive(Clone)] before struct User {...}.

like image 36
DK. Avatar answered Jun 18 '26 21:06

DK.