Type annotations needed when providing None for an optional function as argument

I want to create a function which accepts an optional callback function as argument. When I provide a function the code compiles without error. But when I provide None, then I get a compile error.


#[derive(Debug)]
pub struct AdvReader<F: Fn(&[u8]) -> bool + Send + 'static>
{
    fn_block_mode: Option<F>,
}

impl<F> AdvReader<F>
where F: Fn(&[u8]) -> bool + Send + 'static
{
    pub fn new(fn_block_mode: Option<F>) -> Self {
        Self {
            fn_block_mode
        }
    }
}

fn main() {
    let reader = AdvReader::new(None);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0284]: type annotations needed: cannot satisfy `for<'r> <_ as FnOnce<(&'r [u8],)>>::Output == bool`
  --> src/main.rs:19:18
   |
11 |     pub fn new(fn_block_mode: Option<F>) -> Self {
   |     -------------------------------------------- required by `AdvReader::<F>::new`
...
19 |     let reader = AdvReader::new(None);
   |                  ^^^^^^^^^^^^^^ cannot satisfy `for<'r> <_ as FnOnce<(&'r [u8],)>>::Output == bool`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0284`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

How can I solve this?

The direct answer is that you can provide a Type to the None.

let reader = AdvReader::new(None as Option<fn(&[u8]) -> bool>);

But often you might want to structure your interface with a constant that you can pass instead.

It can't figure out what the F in AdvReader<F> is when you give it None. It could be anything that meets your trait bounds, and there are many possibilities. The same will be true of any generic.

If I replace all your bounds with Default, for example, the same error results.

#[derive(Debug)]
pub struct AdvReader<F: Default>
{
    fn_block_mode: Option<F>,
}

impl<F> AdvReader<F>
where F: Default
{
    pub fn new(fn_block_mode: Option<F>) -> Self {
        Self {
            fn_block_mode
        }
    }
}

fn main() {
    let reader = AdvReader::new(None);
}

(Note that the type of None is Option<F>::None for some generic F. It's not a type on its own.)

2 Likes

I've tried this. But now I get another error message:


#[derive(Debug)]
pub struct AdvReader<F: Fn(&[u8]) -> bool + Send + 'static>
{
    fn_block_mode: Option<F>,
}

impl<F> AdvReader<F>
where F: Fn(&[u8]) -> bool + Send + 'static
{
    pub fn new(fn_block_mode: Option<F>) -> Self {
        Self {
            fn_block_mode
        }
    }
}

fn main() {
    let reader = AdvReader::new(None as Option<dyn Fn(&[u8]) -> bool + Send + 'static>);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `(dyn for<'r> Fn(&'r [u8]) -> bool + Send + 'static)` cannot be known at compilation time
   --> src/main.rs:19:41
    |
19  |     let reader = AdvReader::new(None as Option<dyn Fn(&[u8]) -> bool + Send + 'static>);
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `(dyn for<'r> Fn(&'r [u8]) -> bool + Send + 'static)`

error[E0277]: the size for values of type `dyn for<'r> Fn(&'r [u8]) -> bool + Send` cannot be known at compilation time
  --> src/main.rs:19:33
   |
11 |     pub fn new(fn_block_mode: Option<F>) -> Self {
   |     -------------------------------------------- required by `AdvReader::<F>::new`
...
19 |     let reader = AdvReader::new(None as Option<dyn Fn(&[u8]) -> bool + Send + 'static>);
   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn for<'r> Fn(&'r [u8]) -> bool + Send`

error[E0277]: the size for values of type `dyn for<'r> Fn(&'r [u8]) -> bool + Send` cannot be known at compilation time
  --> src/main.rs:19:18
   |
3  | pub struct AdvReader<F: Fn(&[u8]) -> bool + Send + 'static>
   |                      - required by this bound in `AdvReader`
...
19 |     let reader = AdvReader::new(None as Option<dyn Fn(&[u8]) -> bool + Send + 'static>);
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `Sized` is not implemented for `dyn for<'r> Fn(&'r [u8]) -> bool + Send`
help: consider relaxing the implicit `Sized` restriction
   |
3  | pub struct AdvReader<F: Fn(&[u8]) -> bool + Send + 'static + ?Sized>
   |                                                            ^^^^^^^^

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground`

To learn more, run the command again with --verbose.

dyn Trait are dynamically sized, so you need to store it behind some indirection like in a Box:

 fn main() {
-    let reader = AdvReader::new(None as Option<    dyn Fn(&[u8]) -> bool + Send + 'static >);
+    let reader = AdvReader::new(None as Option<Box<dyn Fn(&[u8]) -> bool + Send + 'static>>);
 }

But why would you do that, when there's a much simpler solution:

let reader = AdvReader::new(None::<fn(&[u8]) -> bool>);
3 Likes

you can also provide default for F

#[derive(Debug)]
pub struct AdvReader<F: Fn(&[u8]) -> bool + Send + 'static = fn(&[u8]) -> bool>
{
    fn_block_mode: Option<F>,
}

No, that doesn't work, because the default is not being applied at that point.

1 Like

I can's speak for the OP but they came back with the dyn in reply to function pointers being suggested already, so I assumed they have a reason for the switch.

I think the confusion at the root of this question comes down to the difference between fn and Fn. I remember this tripped me up when I was starting out.

I suggested:

let reader = AdvReader::new(None as Option<fn(&[u8]) -> bool>);

and the original poster replied:

but in actuality, they tried this:

let reader = AdvReader::new(None as Option<dyn Fn(&[u8]) -> bool + Send + 'static>);

Bottom line. Fn is a trait that bounds function pointers and closures, and fn is the syntax to declare a concrete function pointer type. But many newcomers (myself in the past included) mix them up.

1 Like

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.