Forwarding mutability through callback?

Hi, there's this bit of code, that I can't figure out how to make work easily, without compromising v2's immutability:

fn foo(v1: &mut T, v2: &T, field_getter: &dyn Fn(&mut T) -> &mut U) {
    *getter(v1) = *getter(v2); // v2 is not mut

I guess I could use std::ops::Index[Mut], but it feels like it's a bit too heavyweight just to make a couple of lines work (it's just some local logic inside a toy program). Is it my only choice or are there simpler alternatives?

But if I were to use Index[Mut], would I have to essentially duplicate the exact same logic in both traits?

As you have observed, this is not possible with a single closure. You can either use two closures, or you can make your own trait.

Yes, despite the similarity of:

  • |it: &    ...| &    it <field or index>
  • |it: &mut ...| &mut it <field or index>

(That is, only the <field or index> part seems relevant here, and it looks like there should be a common thing between the two), it turns out that type-wise, these things are very different, since the former offers a shared part out of a shared whole, vs., the latter one offering an exclusive part out of an exclusive whole.

If you feel like avoiding the "redundancy" of code duplication when the syntax of both accesses is so similar, then you could use "syntax-based operators", i.e., macros:

fn main ()
    let mut v1 = [42, 42];
    let v2 = [27, 27];
    foo!(v1, v2, |$it| $it[1]);
    assert_eq!(v1, [42, 27]);

    let mut v1 = (42, 42);
    let v2 = (27, 27);
    foo!(v1, v2, |$it| $it.1);
    assert_eq!(v1, (42, 27));

I was kinda hoping for some way to autogenerate the two variants as needed through generics despite their differences, without resorting to macros, but oh well. Thanks for the help!

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.