How does one move (instead of clone) one field in each element of a vector to a new vector ?
Here is an example of what I am trying to do:
// StringInfo
#[derive(Debug, Clone)]
struct StringInfo {
index : usize ,
value : String ,
}
//
// This method clones strings that will be dropped when it returns.
fn vec_string_info_clone( vec_string : Vec<String> ) -> Vec<StringInfo>
{ let mut vec_string_info : Vec<StringInfo> = Vec::new();
for i in 0 .. vec_string.len() {
vec_string_info.push( StringInfo{ index : i, value : vec_string[i].clone() } );
}
vec_string_info
}
//
// This method does not clone the strings but
// it returns the vector in the reverse of the desired order.
fn vec_string_info_pop( mut vec_string : Vec<String> ) -> Vec<StringInfo>
{ let mut vec_string_info : Vec<StringInfo> = Vec::new();
let len = vec_string.len();
for i in 0 .. len {
let string = vec_string.pop().unwrap();
vec_string_info.push( StringInfo{ index : len - i - 1, value : string } );
}
vec_string_info
}
fn main() {
//
let vec_string = vec![ "zero".to_string(), "one".to_string() ];
let vec_string_info = vec_string_info_clone( vec_string );
println!( "{:?}", vec_string_info );
//
let vec_string = vec![ "zero".to_string(), "one".to_string() ];
let vec_string_info = vec_string_info_pop( vec_string );
println!( "{:?}", vec_string_info );
}
Indexing with [i] is generally inefficient and inflexible in Rust. Constructing by push() isn't great either if you don't reserve capacity ahead of time.
You can use vec.into_iter().map(…).collect() to transform content of a Vec without cloning the contents. It can optimize very well, and sometimes even reuse Vec's allocation.
Other useful functions are .partition() instead of collect() to split non-contiguous elements into two vecs.
You can't leave holes when moving elements out of a Vec. If you have to, then swap_remove() is relatively cheap (but use pop() if you don't need a random order and can take from the end). std::mem::take() may be useful for taking individual fields if they have a cheap default value.
vec.retain_mut() can be useful to take fields and remove leftover elements cheaply.
In other situations, for instance for an arbitrary-order access, as long as you have mutable access, you can avoid a clone of a String value by instead replacing the original with an empty String (which in Rust doesn’t require any allocation costs to create).
// minimally changed from your `…_clone` variant
fn vec_string_info_take(mut vec_string: Vec<String>) -> Vec<StringInfo> {
let mut vec_string_info: Vec<StringInfo> = Vec::new();
for i in 0..vec_string.len() {
vec_string_info.push(StringInfo {
index: i,
value: std::mem::take(&mut vec_string[i]),
});
}
vec_string_info
}
This uses the mem::take method – the more general procedure of “take ownership by providing replacement value” is also available via mem::replace (and mem::swap), whereas mem::take is a convenience wrapper that chooses the Default::default value for replacement.
If the value in question were an Option, there’s a .take() method as well.