I have a simple set of sample code that works great in the Playground for swapping elements between two vector members of two different structures. My problem is that I'm finding it very difficult to modify the code to allow it to swap elements between two elements in the same structure ( i.e. same vector. )
In general, I'm still having a hard time grasping how lifetimes must be used in functions involving structures holding vectors, so if any of you rust experts can help, I would really appreciate some help. ( I'm doing everything I can to resist using unsafe (raw pointers) but this example has me stumped.)
First the sample code that works great to swap between two different structures with vectors.
use std::mem;
#[derive(Debug)]
struct Bar {
d: u32
}
#[derive(Debug)]
struct Foo {
data: Vec<Bar>,
}
impl Foo {
fn get_swap_target(&mut self, idx: usize) -> &mut Bar {
&mut self.data[idx]
}
}
fn main() {
let mut foo1 = Foo{ data: vec![Bar{ d: 10 }, Bar{ d: 20 }], };
let mut foo2 = Foo{ data: vec![Bar{ d:100 }, Bar{ d: 200} ], };
println!("before: foo1 is {:?}", foo1);
println!("before: foo2 is {:?}", foo2);
let swap1 = foo1.get_swap_target(0);
let swap2 = foo2.get_swap_target(0);
mem::swap(swap1, swap2);
println!("after: foo1 is {:?}", foo1);
println!("after: foo2 is {:?}", foo2);
}
Here's it's output:
before: foo1 is Foo { data: [Bar { d: 10 }, Bar { d: 20 }] }
before: foo2 is Foo { data: [Bar { d: 100 }, Bar { d: 200 }] }
after: foo1 is Foo { data: [Bar { d: 100 }, Bar { d: 20 }] }
after: foo2 is Foo { data: [Bar { d: 10 }, Bar { d: 200 }] }
Now, when I modify the code to operate on a single structure and vector, I run into all sorts of problems. Here is the most simple attempt:
use std::mem;
#[derive(Debug)]
struct Bar {
d: u32
}
#[derive(Debug)]
struct Foo {
data: Vec<Bar>,
}
impl Foo {
fn get_swap_target(&mut self, idx: usize) -> &mut Bar {
&mut self.data[idx]
}
}
fn main() {
let mut foo1 = Foo{ data: vec![Bar{ d: 10 }, Bar{ d: 20 }], };
println!("before: foo1 is {:?}", foo1);
let swap1 = foo1.get_swap_target(0);
let swap2 = foo1.get_swap_target(1);
mem::swap(swap1, swap2);
println!("after: foo1 is {:?}", foo1);
}
It fails to compile with the following error:
error[E0499]: cannot borrow `foo1` as mutable more than once at a time
--> src/main.rs:24:17
|
23 | let swap1 = foo1.get_swap_target(0);
| ---- first mutable borrow occurs here
24 | let swap2 = foo1.get_swap_target(1);
| ^^^^ second mutable borrow occurs here
25 |
26 | mem::swap(swap1, swap2);
| ----- first borrow later used here
Seeing this error I used the following code to return the swap targets as a pair using a single function.
use std::mem;
#[derive(Debug)]
struct Bar {
d: u32
}
#[derive(Debug)]
struct Foo {
data: Vec<Bar>,
}
impl Foo {
fn get_swap_target_pair(&mut self, idx1: usize, idx2: usize) -> (&mut Bar, &mut Bar) {
(&mut self.data[idx1], &mut self.data[idx2])
}
}
fn main() {
let mut foo1 = Foo{ data: vec![Bar{ d: 10 }, Bar{ d: 20 }], };
println!("before: foo1 is {:?}", foo1);
let (swap1, swap2) = foo1.get_swap_target_pair(0, 1);
mem::swap(swap1, swap2);
println!("after: foo1 is {:?}", foo1);
}
It also fails to compile but provides some possible clues about lifetime concerns.
13 | fn get_swap_target_pair(&mut self, idx1: usize, idx2: usize) -> (&mut Bar, &mut Bar) {
| - let's call the lifetime of this reference `'1`
14 | (&mut self.data[idx1], &mut self.data[idx2])
| ----------------------------^^^^^^^^^-------
| | | |
| | | second mutable borrow occurs here
| | first mutable borrow occurs here
| returning this value requires that `self.data` is borrowed for `'1`
I thought maybe if I changed get_swap_target_pair() to use a single lifetime might help. Here's the new version of that function (rest of code untouched.)
fn get_swap_target_pair<'a>(&'a mut self, idx1: usize, idx2: usize) -> (&'a mut Bar, &'a mut Bar) {
(&mut self.data[idx1], &mut self.data[idx2])
}
Here's the compiler error I get using this change:
|
13 | fn get_swap_target_pair<'a>(&'a mut self, idx1: usize, idx2: usize) -> (&'a mut Bar, &'a mut Bar) {
| -- lifetime `'a` defined here
14 | (&mut self.data[idx1], &mut self.data[idx2])
| ----------------------------^^^^^^^^^-------
| | | |
| | | second mutable borrow occurs here
| | first mutable borrow occurs here
| returning this value requires that `self.data` is borrowed for `'a`
My question boils down to what is the simplest (smallest) change to have my code at the top work with a single structure and vector and two different elements?