Quick way to take a specific variable from a vector of structs?

So say I have this struct:

struct ParamStruct{
    pub key: i32,
    pub value: String,
}

And I also have a vector vec_params containing several values of the struct.
Now, if I want a vector containing only the key variable in that Struct, I can do:

let mut vec_key:Vec<i32>=Vec::new();
for i in 0..vec_params.len(){
    vec_key.push(vec_params[i].key)
}

Which is fine and all, and it's very trivial, but are there any quicker or methodological way? 4 lines of code is not much but I just want to know if there is any quick syntax to do it.

let vec_key: Vec<i32> = vec_params.into_iter().map(|p| p.key).collect();

Or, if you want to be able to use vec_params afterward (this only works because i32: Copy):

let vec_key: Vec<i32> = vec_params.iter().map(|ParamStruct { ref key, .. }| key).copied().collect();

To explain step-by-step:

  • into_iter (from the IntoIterator trait) consumes vec_params and turns it into an iterator that yields each of its entries in turn
    • iter is a method on Vec<T> that creates an iterator yielding references &T instead of owned values, so it doesn't consume the vector. copied (from Iterator) turns an iterator of &T where T: Copy into an iterator of T.
  • map (from the Iterator trait) transforms each value yielded by the previous iterator using a closure, in this case |p| p.key
  • collect (also from Iterator; uses the FromIterator implementation for Vec<T>) is the inverse of into_iter: it turns an iterator into a collection, in this case Vec<i32>

This is a very common way of achieving "do something for each value in a collection" in Rust:

  1. turn the collection into an iterator
  2. use map and other Iterator methods to do the thing
  3. (optional) create a new collection using collect
4 Likes

Or, if you prefer, the same thing using pattern matching instead of field access:

    let vec_key: Vec<i32> = vec_params
        .into_iter()
        .map(|ParamStruct { key, .. }| key)
        .collect();
3 Likes