It often happens to me that I need to write a method that modifies some struct but the method needs to be pointed to a particular value contained inside of it with a mutable reference. The borrow checker doesn't let me do that.
I do this all the time in Go, Python, etc.. Now, I know Rust is a different language and I shouldn't necessarily try to translate everything over. I was just curious to know if an idiomatic solution exists.
Yes it is possible to pass the method some information that lets it get a reference to the target value by itself. Maybe passing an index or a key. But that sounds like a workaround honestly.
Here's an example (the simplest I could come up with):
#![allow(unused)]
struct DataStructure {
vec_a: Vec<i32>,
vec_b: Vec<i32>,
// How many times `[DataStructure::clear]` has been called
n_clear: u32,
}
impl DataStructure {
fn clear(&mut self, vec: &mut Vec<i32>) {
vec.clear();
self.n_clear += 1;
}
}
fn main() {
let mut ds = DataStructure {
vec_a: vec![32, 11],
vec_b: vec![63, 255, 512],
n_clear: 0,
};
ds.clear(&mut ds.vec_a);
}
Playground link:
I could maybe pass in an enum to tell the method which of the two vectors I want cleared but I have to define a whole new enum just for that!
Also, performance-wise this solution doesn't seem ideal because of the branching that I would have to do inside the method.
And also: this example is fairly simple but imagine the method was defined on a tree and needed to be pointed to a particular node. Yes it would be possible to pass in some kind of information that says: "from the root, go down the first child, then the second child of that, etc..." but isn't this incredibly boilerplatey assuming I already have a reference to the node? Maybe I don't even know the "indications" to reach that node and I would have to compute them just to be able to call the method.
Now yes, this is not allowed because I have aliasing references, I understand that. But is it really unsafe if want to use that second reference just to point the method to a target value?
Is there a way to "transmute" a &mut T
or a &T
into one of the same type but that falls under the umbrella of borrowing that &mut self
has?
In other words: is there a way to take in a &mut self
and then craft a &mut T
from it, by using some sort of &T
given to the method just to point it to a target value?
Here's what I mean (pardon the bad hypothetical syntax):
fn clear(&mut self, vec: &Vec<i32>) {
let mut vec_crafted = self.[vec];
vec_crafted.clear();
self.n_clear += 1;
}
where vec_crafted
is borrowed from self
and then dropped before adding to n_clear
just like:
fn clear(&mut self) {
let mut vec_a = &mut self.vec_a;
vec_a.clear();
self.n_clear += 1;
}