[solved] How to pass None to a function when an Option<Closure> is expected?


#1

Hello everybody,

I’m fighting with a function that takes an Option<FnMut(String) -> ()> as parameter when I want to pass None, because the type of T cannot be deferred.

fn maybe_closure<T: FnMut(String) -> ()>(closure: Option<T>) -> () {
...
}

// Works
maybe_closure(Some(...));

// Does not compile
maybe_closure(None);

The compiler tells me

11  |         maybe_closure(None);
    |                  ^^^^^^^^^^^^^^^^^^ cannot infer type for `T`
    |
    = note: type annotations or generic parameter binding required

I get that. But I have no idea how to actually specify T, because if I use None::<FnMut(String) -> () the compiler explains

    |
11  |         maybe_closure("Deutsche Bank", None::<FnMut(String) -> ()>);
    |                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Sized` is not implemented for `std::ops::FnMut(std::string::String)`
    |
    = note: `std::ops::FnMut(std::string::String)` does not have a constant size known at compile-time
    = note: required by `std::prelude::v1::None`

I also get that.

But I have no idea how to solve this issue satisfying the compiler and me.

Any help is appreciated.
Cheers Lukas


#2

I think None::<Box<FnMut(String) -> ()>> should work. The error is because the size of the closure is unknown at compile time, so you have to box it.
Someone correct me if I’m wrong 'cause I’m not so expert.


#3

That’s because Rust doesn’t know what is the type of T. An easy workaround would be to provide any type that fits T, the easiest pick would be function literal pointer.

maybe_closure(None::<fn(_)>);

Unfortunately, this is ugly, you may want to try providing a different API, depending on what None actually means in your API.


#4

Thanks @garro, but that does not adhere to the function’s signature, because now an Option<Box<T>> is passed instead of Option<T>.

I’d rather not change the signature of the function, but convince the compiler :slight_smile:


#5

Thanks @xfix, that does the trick and it’s not the worst I’ve seen :slight_smile:

The semantics is that the real function contains a long running algorithm and may or may not report progress with a callback passed as a closure.


#6

If semantics of None are essentially doing nothing, then don’t accept Option, and just specify empty function like || {} as an argument. As the function is generic over types, and closures have different types the compiler will be able to optimize that out by inlining. No need to micro-optimise


#7

I actually prefer Option because it better communicates intent, but I’ll keep your idea in mind.


#8

T = Box<FnMut(String) -> ()> satisfies T: FnMut(String) -> (). It wouldn’t require changing the code. But fn(String) is better


#9

I hit this exact same issue while adding a new test in my code. I had a helper function and wanted to add an optional function to invoke at a certain point. After struggling with the same errors you did I gave up and just defined a fn nothing(...) to use instead of None.