I'm trying to implement a type that supports operations like this:
let mut c = MyContainer::new(...);
let handle = c.find(key);
println!("{}", handle.value);
c.remove(handle);
This is kind of like how C++ containers work, by returning iterator
s and letting you pass them to erase()
. It's important for my use case for a few reasons, mainly because find()
can be quite expensive, so I don't want to repeat the search like I would have to for something like c.remove(key)
.
The issue with this is that the handle
has references into the container. So a naive implementation fails with "cannot borrow c
as mutable because it is also borrowed as immutable". Here's a complete example:
struct MyContainer(Vec<String>);
struct Handle<'a> {
value: &'a String,
index: usize,
}
impl MyContainer {
fn new(values: Vec<String>) -> Self {
Self(values)
}
fn find(&self, value: &str) -> Option<Handle> {
for (i, s) in self.0.iter().enumerate() {
if s == value {
return Some(Handle {
value: s,
index: i,
})
}
}
None
}
fn remove(&mut self, handle: &Handle) {
self.0.remove(handle.index);
}
}
fn main() {
let mut c = MyContainer::new(vec!["Hello".to_string(), "world".to_string()]);
if let Some(handle) = c.find("world") {
println!("{}", handle.value);
c.remove(&handle);
}
}
Is there an established pattern for situations like this? I searched around but couldn't really find anything.