(Experienced C, C++, Python programmer. New to rust, still trying to wrap my head around lifetimes, borrows, moves, and the ways references are different from C pointers)
I'm trying to represent a list of locations, where each location has a size and offset:
struct FreeLoc {
size: u64,
offset: u64
}
These live in and are owned by a Vec
in another struct. For lookup performance, I want to maintain this list in two separate orderings -- one sorted by size, and the other by offset. I have the owning Vec
(free), and two Vec<&FreeLoc>
to store references to the objects in the owning Vec
, sorted appropriately:
struct FreeList<'a> {
free: Vec<FreeLoc>,
by_size: Vec<&'a FreeLoc>,
by_offset: Vec<&'a FreeLoc>
}
impl<'a> FreeList<'a> {
pub fn new(size: u64) -> Self {
let mut s = Self {
free: vec![ FreeLoc { size: size, offset: 0 }],
by_size: Vec::new(),
by_offset: Vec::new()
};
s.by_size.push(&s.free[0]);
s.by_offset.push(&s.free[0]);
s
}
}
I get the following build errors:
error[E0515]: cannot return value referencing local data `s.free`
--> src/freelist/freelist.rs:31:9
|
28 | s.by_size.push(&s.free[0]);
| ------ `s.free` is borrowed here
...
31 | s
| ^ returns a value referencing data owned by the current function
error[E0505]: cannot move out of `s` because it is borrowed
--> src/freelist/freelist.rs:31:9
|
21 | impl<'a> VecFreeList<'a> {
| -- lifetime `'a` defined here
...
28 | s.by_size.push(&s.free[0]);
| ------ borrow of `s.free` occurs here
...
31 | s
| ^
| |
| move out of `s` occurs here
| returning this value requires that `s.free` is borrowed for `'a`
error[E0515]: cannot return value referencing local data `s.free`
--> src/freelist/freelist.rs:31:9
|
29 | s.by_offset.push(&s.free[0]);
| ------ `s.free` is borrowed here
30 |
31 | s
| ^ returns a value referencing data owned by the current function
There are several questions here:
- Is the error with line 31 a side effect of
s
being allocated on the stack? When ::new returns, the physical memory location of s moves, and therefore the references in s.by_size and s.by_offset are no longer valid?
31 | s
| ^ returns a value referencing data owned by the current function
- What is the "right" way to get around this problem? Allocate the
FreeLoc
s on the heap using Box? And therefore theFreeList
turns into:
struct FreeList<'a> {
free: Vec<Box<FreeLoc>>,
by_size: Vec<&'a Box<FreeLoc>>,
by_offset: Vec<&'a Box<FreeLoc>>
}
- Is this really the right way to handle heap allocation in rust? Seems super clunky.