I have a problem with self
borrowing in a match
expression:
fn add_once(&'t mut self, p_name: &'t str) -> Box<Element> {
match self.get(p_name) {
Some(x) => Box::new(*x),
None => self.add(p_name),
}
}
The signature of the get()
and add()
functions are:
fn get(&self, p_name: &str) -> Option<&Element>
fn add(&'t mut self, p_name: &'t str) -> Box<Element>
The compiler refuses this code:
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> src/main.rs:38:21
|
36 | match self.get(p_name) {
| ---- immutable borrow occurs here
37 | Some(x) => Box::new(*x),
38 | None => self.add(p_name),
| ^^^^ mutable borrow occurs here
39 | }
40 | }
| - immutable borrow ends here
I get that, but I don't see how I can rewrite the match
expression.
In a related question, it was solved by having the match
return a value and then calling the function. However, that doesn't work here because the meaning of the conditional is not to choose a value but selectively execute an action.
The full code sample is below:
struct Element<'e> {
name: &'e str,
}
impl<'e> Element<'e> {
fn new(p_name: &str) -> Element {
Element { name: p_name }
}
}
struct Top<'t> {
list: Vec<Element<'t>>,
}
impl<'t> Top<'t> {
fn new() -> Top<'t> {
Top { list: vec![] }
}
fn get(&self, p_name: &str) -> Option<&Element> {
for element in self.list.iter() {
if element.name == p_name {
return Some(element);
}
}
None
}
fn add(&'t mut self, p_name: &'t str) -> Box<Element> {
let new_element = Box::new(Element::new(p_name));
self.list.push(*new_element);
return new_element;
}
fn add_once(&'t mut self, p_name: &'t str) -> Box<Element> {
match self.get(p_name) {
Some(x) => Box::new(*x),
None => self.add(p_name),
}
}
}
fn main() {
let mut t = Top::new();
let plop1 = t.add_once("plop1");
let plop2 = t.add_once("plop1");
}
match
should return the same type. Similarly, I am surprised thatadd
compiles as you firstpush
into the vector and then return; however it seems to me that pushing into the vector should invalidate (move) the content of the box... Shouldn'tadd
return&Element
and the result ofadd_once
be&Element
? – Matthieu M.Element
isCopy
, so*new_element
returns a copy of the element. – Vladimir MatveevCopy
was not yet opt-in. Still, it seems to me this indicate a design flaw:Top
seems like it should be generic, and work on non-Copy
types. – Matthieu M.Copy
types. – Tifauv'add
andadd_once
to return&Element
, but couldn't get it working. – Tifauv'