Is it possible to replace all function arguments with just one struct argument?

I have function with > 10 arguments, like this:

fn f(a1: &T1, a2: &T2, ... a6: &T6, a7: &mut T7, ... a11: &mut T11) {...}

and I call it like this:

fn call_f(a1: &T1, a2: &T2, ... a6: &T6, a7: &mut T7, ... a11: &mut T11)
{
   {
      let tmp = ...;
      let a2 = &tmp;
      f(a1, a2, ...);
   }
   f(a1, a2, ...);
}

all works fine, but I need to call f three more times.

So I want to refactor it like this:

struct Context<'a> {
  a1: &'a T1,
  a2: &'a T2,
...
}

In my imagination it would be as simple as:

fn call_f(a1: &T1, a2: &T2, ... a6: &T6, a7: &mut T7, ... a11: &mut T11)
{
  let mut ctx = Context {a1, a2, ... };
   {
      let tmp = ...;
      ctx.a2 = &tmp;
      f(&mut ctx);
   }
   f(&mut ctx);
}

But I suppose you see the problem, a2 should has variable lifetime to make it work. Any way to solve this problem, to make possible to change a2 field on the fly?

You can't solve this with (fancy) lifetimes, I think. But simply copy your Context struct:

#[derive(Clone, Copy)]
struct Context<'a> {
  a1: &'a T1,
  a2: &'a T2,
...
}

fn call_f(a1: &T1, a2: &T2, ... a6: &T6, a7: &mut T7, ... a11: &mut T11)
{
  let mut ctx = Context {a1, a2, ... };
   {
      let mut my_ctx = ctx; // Copy

      let tmp = ...;
      my_ctx.a2 = &tmp; // Modify local copy

      f(&mut my_ctx); // Use local copy
   }

   f(&mut ctx); // Use original
}

This is little bit error prone, because your original context is mut. I suggest using a non-mutable ctx and always copy to a local mutable before use. Or make the consuming function not needing a mutable reference.

Here's one way. And with that tool in hand, you could consider making f take Context<'_> by value.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.