Skip to content

Instantly share code, notes, and snippets.

@irh
Created September 29, 2022 08:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save irh/aa3acf30bf0a1382d2dae8d11d786d38 to your computer and use it in GitHub Desktop.
Save irh/aa3acf30bf0a1382d2dae8d11d786d38 to your computer and use it in GitHub Desktop.
An example of implementing a method that accepts closures with different arguments.
// An example of implementing a method that accepts closures with different input arguments.
// The trick to avoid Rust complaining about conflicting implementations is to specify
// the arguments for each specialization in a separate type parameter.
// See https://geo-ant.github.io/blog/2021/rust-traits-and-variadic-functions/
fn main() {
let mut foo = Foo::default();
foo.add_fn(|| 0);
foo.add_fn(|a| a);
foo.add_fn(|a, b| a + b);
foo.add_fn(|a, b, c| a + b + c);
for f in &foo.functions {
println!("{}", f());
}
}
struct Foo {
// A collection of functions that return an integer
functions: Vec<Box<dyn Fn() -> i32>>,
// Some default values that can be passed into the functions
a: i32,
b: i32,
c: i32,
}
impl Default for Foo {
fn default() -> Self {
Self {
functions: Vec::default(),
a: 1,
b: 10,
c: 100,
}
}
}
// A trait for adding a function, implemented with different specializations by Foo
trait AddFn<F, Args> {
fn add_fn(&mut self, f: F);
}
// No args
impl<F> AddFn<F, ()> for Foo
where
F: Fn() -> i32 + 'static,
{
fn add_fn(&mut self, f: F) {
self.functions.push(Box::new(move || f()));
}
}
// 1 arg
impl<F> AddFn<F, i32> for Foo
where
F: Fn(i32) -> i32 + 'static,
{
fn add_fn(&mut self, f: F) {
let a = self.a;
self.functions.push(Box::new(move || f(a)));
}
}
// 2 args
impl<F> AddFn<F, (i32, i32)> for Foo
where
F: Fn(i32, i32) -> i32 + 'static,
{
fn add_fn(&mut self, f: F) {
let a = self.a;
let b = self.b;
self.functions.push(Box::new(move || f(a, b)));
}
}
// 3 args
impl<F> AddFn<F, (i32, i32, i32)> for Foo
where
F: Fn(i32, i32, i32) -> i32 + 'static,
{
fn add_fn(&mut self, f: F) {
let a = self.a;
let b = self.b;
let c = self.c;
self.functions.push(Box::new(move || f(a, b, c)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment