EN VI

Rust - How do I create a static constant closure?

2024-03-12 00:00:06
Rust - How do I create a static constant closure?

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!

Answer

Login


Forgot Your Password?

Create Account


Lost your password? Please enter your email address. You will receive a link to create a new password.

Reset Password

Back to login