Swapping between Vec elements in Rust can be a little tricky. The get method returns Option<&T>, and the lone swap method accepts an index and a value – not a reference. There is an alternative, though. But it uses unsafe codes.
Swap Between Vec Elements
When we swap between Vec elements, it means any two items replace each other’s value. We can do it safely or unsafely.
Safe Swap
A safe swap between Vec elements in Rust means we are not using the unsafe keyword. Consider the following codes. They clone any two items and replace each other’s value using the swap method.
1 2 3 4 5 6 7 8 9 10 11 12 13 | fn main() { let mut vec_val = vec![1, 2, 3]; println!("{:?}", vec_val); let one = vec_val.get(0).cloned().unwrap(); let two = vec_val.get(1).cloned().unwrap(); vec_val.swap(0,two); vec_val.swap(1,one); println!("{:?}", vec_val); } |
The codes generate the following output.
1 2 | [1, 2, 3] [3, 2, 1] |
Unsafe Swap
The next implementation requires creating a trait and implementing it for a specific type of Vec. Let’s say we have a struct Person and an instance of Vec<Person>.
1 2 3 4 5 6 7 8 9 | #[derive(Debug, Clone)] struct Person { name: String } let mut vec_val = vec![ Person { name: "Karl".to_string() }, Person { name: "Joan".to_string() }, Person { name: "Andrew".to_string()}]; |
We want, for instance, to swap between the first and third elements from
1 | [Person { name: "Karl" }, Person { name: "Joan" }, Person { name: "Andrew" }] |
to
1 | [Person { name: "Andrew" }, Person { name: "Joan" }, Person { name: "Karl" }] |
we need to extend Vec.
First, we need to create a trait with one method that accepts the indexes of elements to swap.
1 2 3 | trait ElementSwapper{ fn swap(&mut self, a: usize, b: usize); } |
Then, we need to implement the trait for Vec<Person>.
1 2 3 4 5 6 7 8 9 | impl ElementSwapper for Vec<Person> { fn swap(&mut self, a: usize, b: usize) { unsafe { let pa: *mut Person = &mut self[a]; let pb: *mut Person = &mut self[b]; std::ptr::swap(pa, pb); } } } |
Lastly, we can swap between Vec elements in Rust in the following way.
1 2 3 4 5 6 7 8 9 10 | fn main() { let mut vec_val = vec![ Person { name: "Karl".to_string() }, Person { name: "Joan".to_string() }, Person { name: "Andrew".to_string()}]; println!("{:?}", vec_val); vec_val.swap(0, 2); println!("{:?}", vec_val); } |
The codes generate the following output.
1 2 | [Person { name: "Karl" }, Person { name: "Joan" }, Person { name: "Andrew" }] [Person { name: "Andrew" }, Person { name: "Joan" }, Person { name: "Karl" }] |