How do I store a closure in a struct in Rust?
ClosuresRustClosures Problem Overview
Before Rust 1.0, I could write a structure using this obsolete closure syntax:
struct Foo {
pub foo: |usize| -> usize,
}
Now I can do something like:
struct Foo<F: FnMut(usize) -> usize> {
pub foo: F,
}
But then what's the type of a Foo
object I create?
let foo: Foo<???> = Foo { foo: |x| x + 1 };
I could also use a reference:
struct Foo<'a> {
pub foo: &'a mut FnMut(usize) -> usize,
}
I think this is slower because
- the pointer dereference
- there's no specialization for the type of
FnMut
that actually ends up being used
Closures Solutions
Solution 1 - Closures
Complementing the existing answer with some more code for demonstration purposes:
Unboxed closure
Use a generic type:
struct Foo<F>
where
F: Fn(usize) -> usize,
{
pub foo: F,
}
impl<F> Foo<F>
where
F: Fn(usize) -> usize,
{
fn new(foo: F) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
Boxed trait object
struct Foo {
pub foo: Box<dyn Fn(usize) -> usize>,
}
impl Foo {
fn new(foo: impl Fn(usize) -> usize + 'static) -> Self {
Self { foo: Box::new(foo) }
}
}
fn main() {
let foo = Foo {
foo: Box::new(|a| a + 1),
};
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
Trait object reference
struct Foo<'a> {
pub foo: &'a dyn Fn(usize) -> usize,
}
impl<'a> Foo<'a> {
fn new(foo: &'a dyn Fn(usize) -> usize) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: &|a| a + 1 };
(foo.foo)(42);
(Foo::new(&|a| a + 1).foo)(42);
}
Function pointer
struct Foo {
pub foo: fn(usize) -> usize,
}
impl Foo {
fn new(foo: fn(usize) -> usize) -> Self {
Self { foo }
}
}
fn main() {
let foo = Foo { foo: |a| a + 1 };
(foo.foo)(42);
(Foo::new(|a| a + 1).foo)(42);
}
> what's the type of a Foo
object I create?
It's an unnameable, automatically generated type.
> I could also use a reference [...] slower because [...] the pointer deref [...] no specialization
Perhaps, but it can be much easier on the caller.
See also:
- https://stackoverflow.com/q/27994509/155423
- https://stackoverflow.com/q/25445761/155423
- https://stackoverflow.com/q/49980850/155423
- https://stackoverflow.com/q/41082409/155423
- https://stackoverflow.com/q/27874683/155423
- https://stackoverflow.com/q/52696907/155423
- https://stackoverflow.com/q/50650070/155423
Solution 2 - Closures
For what type you'd use in your third code snippet, there isn't one; closure types are anonymous and cannot be directly named. Instead, you'd write:
let foo = Foo { foo: |x| x + 1 };
If you're writing code in a context where you need to specify that you want a Foo
, you'd write:
let foo: Foo<_> = Foo { foo: |x| x + 1 };
The _
tells the type system to infer the actual generic type for you.
The general rule of thumb as to which to use, in descending order:
- Generic parameters:
struct Foo<F: FnMut(usize) -> usize>
. This is the most efficient, but it does mean that a specificFoo
instance can only ever store one closure, since every closure has a different concrete type. - Trait references:
&'a mut dyn FnMut(usize) -> usize
. There's a pointer indirection, but now you can store a reference to any closure that has a compatible call signature. - Boxed closures:
Box<dyn FnMut(usize) -> usize>
. This involves allocating the closure on the heap, but you don't have to worry about lifetimes. As with a reference, you can store any closure with a compatible signature.
Before Rust 1.0
Closures that used the ||
syntax were references to closures stored on the stack, making them equivalent to &'a mut FnMut(usize) -> usize
. Old-style proc
s were heap-allocated and were equivalent to Box<dyn FnOnce(usize) -> usize>
(you can only call a proc
once).