2

I'm trying to declare a const closure so I can use throughout my code:

    impl<T: Default + Copy + Eq> Profiler<T> {
    pub const increase_by_one: dyn Fn(&T) = &|x| {
        *x = *x + 1;
    };

but I'm getting problems in the size not being known at compile time.

I also tried this:

impl<T: Default + Copy + Eq> Profiler<T> {
    pub const increase_by_one: fn(&T) = &|x| {
        *x = *x + 1;
    };

But it says that the type of x must be known.

Is there a way to define a closure inside a generic struct?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • It looks like it works if you add x a type: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7251abaeb584bf4c32e9a3cf1f312f13) – MaxV Oct 09 '20 at 00:17
  • @MaxV any idea on why I cannot add +1 to *x? – Guerlando OCs Oct 09 '20 at 00:45
  • 2
    Because `x` could be any type, so there is no guarantee that `1` or "add" mean anything for type `T`. Look at [`num_traits::identities::One`](https://docs.rs/num-traits/0.2.12/num_traits/identities/trait.One.html) and [`std::ops::Add`](https://doc.rust-lang.org/std/ops/trait.Add.html) for the relevant constraints. – Jmb Oct 09 '20 at 06:31

1 Answers1

3

It isn't possible to define a const closure in Rust today because the type of a closure cannot be named. You could use a function pointer (fn(&T)), but that incurs call time overhead compared to a closure type. You could use a 'static trait object reference (&'static dyn Fn(&T)), but that also has call time overhead and it requires a T: 'static bound.

Fortunately, const closures are never necessary. The only difference between a closure and a fn item is that closures can have state, but consts may not have state, so there's not really any point to combining them. Just use an associated function instead of an associated constant.

impl<T: AddAssign<i32>> Profiler<T> {
    pub fn increase_by_one(x: &mut T) {
        *x += 1;
    }
}

See also

trent
  • 25,033
  • 7
  • 51
  • 90
  • what's the difference between `fn(&T)` and a closure? I thought mine was a closure already – Guerlando OCs Oct 09 '20 at 17:03
  • 1
    `fn(...)` is the type of a function pointer. Closures have unnameable types, but if they don't capture anything from the environment, they can be coerced to function pointers. Function pointers are basically irrelevant to the question at hand, so I don't want to write a long explanation into the answer, but I added some links to other questions about the topic. – trent Oct 09 '20 at 18:29
  • @GuerlandoOCs FYI, I just added another link to a new question that gave me an opportunity to write some of the stuff that was bouncing around in my head yesterday, but wasn't topical for this answer. Maybe it will help. – trent Oct 10 '20 at 22:10
  • @trentcl great answer, thank you. By "call time overhead" am I correct in assuming you are referring to the extra deref required in the case of the function pointer and the vtable dynamic dispatch in the case of the trait object? – U007D Oct 17 '21 at 15:59
  • 1
    @U007D Yes, exactly. – trent Oct 17 '21 at 20:30