How do I create a static constant closure?

Advertisements

Background

I have a struct that stores a couple of references to closures

struct FnThing<'a, F: Fn()> {
    f: &'a F,
}

I want to implement the Default trait for FnThing where f has default value of a no-op ||{} function.

Since f is a reference, I plan to accomplish this by creating a static no-op closure function so that I can set the defualt value as

impl<'a, F: Fn()> Default for FnThing<'a, F> {
    fn default() -> Self {
        Self { f: &NO_OP }
    }
}

First attempt

static NO_OP: impl Fn = ||{};

rust complains that

`impl Trait` only allowed in function and inherent method return types, not in const types

Fair enough

Second attempt

static NO_OP: dyn Fn() = || {};

Now it complains that

the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time

OK, for unknown size, I should use the heap

Third attempt

static NO_OP: Box<dyn Fn()> = Box::new(|| {});

Now it complains

`(dyn Fn() + Send + 'static)` cannot be shared between threads safely

I don’t care about multithreading atm, but it would still be nice if my code was thread safe in case I do in the future. Though I fail understand why this isn’t thread safe.

Fourth attempt

Why not just use a simple function pointer?

static NO_OP: fn() = || {};

impl<'a, F: Fn()> Default for FnThing3<'a, F> {
    fn default() -> Self {
        Self { f: NO_OP }
    }
}

This doesn’t work since fn() and F: Fn() are different types. Following this answer, I try

    fn default() -> Self {
        Self {
            f: (Box::new(NO_OP) as Box<dyn Fn()>).as_ref(),
        }
    }

but it still gives me the error

expected `&F`, found `&dyn Fn()`

Question

I’m out of ideas…
How do I create a static constant closure?

>Solution :

You’re almost there. Your problem right now is that you’re trying to get a generic F: impl Fn(). You can just not write that, since you can’t have a default over every generic type. So just impl Default for the case where F is just fn(), like so:

struct FnThing<'a, F: Fn()> {
    f: &'a F,
}

static NO_OP: fn() = || {};

impl<'a> Default for FnThing<'a, fn()> {
    fn default() -> Self {
        FnThing { f: &NO_OP }
    }
}

I think this is the what you want. Let me know if it works the way you want!

Leave a ReplyCancel reply