Default value for generic field bound by fn trait

I have a struct that has a generic field which is bound by the FnMut trait. I would like to be able to create this struct with some default value for this field - a closure that does nothing. This is currently not working because I cannot define a specific type for the closure. Some ideas on how to change this example such that I can create my struct with some default value for f?

struct UsageOfFunction<F>
where
    F: FnMut(u64) -> (),
{
    f: F,
}
impl<F> UsageOfFunction<F>
where
    F: FnMut(u64) -> (),
{
    fn new(f: F) -> Self {
        Self { f }
    }

    // TODO would be nice to have:
    // fn new_with_empty_f() -> Self {
    //     Self { f: |_| {} }
    // }

    fn do_something(&mut self) {
        // ... do some other stuff here ...
        // somehow create the value 4 and then call the function with that value:
        (self.f)(4);
    }
}

fn main() {
    // some usage:
    let mut usage = UsageOfFunction::new(|x| println!("I just print the value: {}", x));
    usage.do_something();

    // other usage:
    let mut y = 5;
    let mut usage = UsageOfFunction::new(|x| {
        y += x;
    });
    usage.do_something();
    assert_eq!(y, 9);

    // usage in tests (to test behaviour of UsageOfFunction without f):
    let mut usage = UsageOfFunction::new(|_| {});
    // TODO better would be:
    // let mut usage = UsageOfFunction::new_with_empty_f();
    usage.do_something();
}
impl UsageOfFunction<fn(u64)> {
    fn new_with_empty_f() -> Self {
         Self { f: |_| {} }
    }
}

Each closure has it's own type. but an empty closure easily works as a function pointer, which is a concrete type.
You just have to do that in a separate impl block.

2 Likes

True! Thank you so much :slight_smile:

(Edit: Ignore this, it's not ergonomic.)

Or...

impl<F> UsageOfFunction<F>
where
    F: FnMut(u64) -> (),
{
    // instead of `Self`     vvvvvvvvvvvvvvvvvvvvvvvv
    fn new_with_empty_f() -> UsageOfFunction<fn(u64)> {
         UsageOfFunction { f: |_| {} } // <-- similarly
    }
}

with that a bare UsageOfFunction::new_with_empty_f() wont' work, because it can't infer F.
You will at least need UsageOfFunction::<fn(u64)>::new_with_empty_f() to make it work then.

1 Like

Good point.

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.