A few times, I've run into the scenario where an accessor method is needed for both mutable and immutable references.
For ~3 lines it isn't a problem to duplicate the logic, but when the logic gets more complex, it's not nice to copy-paste large blocks of code.
I'd like to be able to re-use the code for both.
Does Rust provide some way handle this better then copy-pasting code, or using unsafe
casts?
e.g.:
impl MyStruct {
pub fn get_foo(&self) -> &Bar {
// ~20 lines of code
// --- snip ---
return bar;
}
pub fn get_foo_mut(&mut self) -> &mut Bar {
// ~20 lines of code
// (exactly matching previous code except `bar` is mutable)
// --- snip ---
return bar;
}
}
Here is a more detailed excerpt of a code-base where an immutable return argument was cast to mutable to support both immutable and mutable versions of a function. This uses a wrapped pointer type (ConstP
and MutP
for immutable and mutable references), but the logic of the function should be clear.
pub fn face_vert_share_loop<V, F>(f: F, v: V) -> LoopConstP
where V: Into<VertConstP>,
F: Into<FaceConstP>
{
into_expand!(f, v);
let l_first = f.l_first.as_const();
let mut l_iter = l_first;
loop {
if l_iter.v == v {
return l_iter;
}
l_iter = l_iter.next.as_const();
if l_iter == l_first {
break;
}
}
return null_const();
}
pub fn face_vert_share_loop_mut(f: FaceMutP, v: VertMutP) -> LoopMutP {
let l = face_vert_share_loop(f, v);
return unsafe {
// Evil! but what are the alternatives?
// Perform an unsafe `const` to `mut` cast :(
// While in general this should be avoided,
// its 'OK' in this case since input is also mutable.
l.as_mut()
};
}
MyStruct
is somehow akin to a map, and the ~20 lines of code you have are used to fetch the reference toBar
? It may because it's morning but I've got some difficulties seeing exactly how things play out here, so it's hard to evaluate the potential answers I come up with... could you come up with a MCVE? – Metametabelconst_cast
in a similar fashion to your example; I'm interested to see what people will manage to do, maybe something with traits (with associated types) is available to abstract over the mutability. – MetametabelSelf
, and then implement it for&MyStruct
and&mut MyStruct
? For example, just writetrait FooGetter { fn get_foo(Self) -> Self { /* generic logic */ } }
and thenimpl FooGetter for &MyStruct {}
andimpl FooGetter for &mut MyStruct {}
. I mean, you just want to abstract over two different types, if they were unrelated, you would just use a trait. Why not do the same here? You'll need to import the trait everywhere to use it, but you can use a prelude for that. – Hebe&
and&mut
, so now you have a genericget
method that doesn't care about mutability and does the right thing. You can now write other traits that require this one, and use this to write generic code that abstracts over mutability. – Hebe