I'm working on a small application where I found myself passing many of the same &mut
arguments to functions over and over. Example:
fn xyz(a: &mut A, b: &mut B) { /* ... */ }
fn bar(a: &mut A, b: &mut B, c: &mut C) { xyz(a, b); /* ... */ }
fn foo(a: &mut A, b: &mut B, c: &mut C) { bar(a, b, c); /* ... */ }
While in my real world case the functions slightly varied in arity between each other, there were always 3-4 arguments in common. I decided to do something that I thought was sensible: wrap the common arguments in a struct
and pass the struct
instead.
struct Context {
a: A,
b: B,
c: C
}
fn xyz(c: &mut Context) { /* ... */ }
fn bar(c: &mut Context) { xyz(c); /* ... */ }
fn foo(c: &mut Context) { bar(c); /* ... */ }
If a function only needs a subset of Context
's arguments and if the call depends on one of them, the borrow checker complains. Here's an example:
struct Context {
f0: HashSet<String>,
f1: HashSet<String>,
}
fn bar(f1: &mut HashSet<String>) {}
fn foo(k: &str, c: &mut Context) {
c.f0.get(k).map(|_| bar(&mut c.f1));
}
error[E0500]: closure requires unique access to `c` but `c.f0` is already borrowed
--> <anon>:11:21
|
11 | c.f0.get(k).map(|_| bar(&mut c.f1));
| ---- ^^^ - - borrow ends here
| | | |
| | | borrow occurs due to use of `c` in closure
| | closure construction occurs here
| borrow occurs here
I understand why the error is happening, but I would like to avoid all the code repetition that happens when passing arguments individually. Note that passing arguments individually does prevent the issue:
fn bar(f1: &mut HashSet<String>) {}
fn foo(k: &str, f0: &mut HashSet<String>, f1: &mut HashSet<String>) {
f0.get(k).map(|_| bar(f1));
}
While not true for this minimal example, using something like Context
increased the readability of my real code significantly, as the function signatures were shorter and code repetition was diminished.
Is there a way to reduce code repetition when multiple functions share a subset of arguments?