How do I store a closure in a struct in Rust?
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:
- How do I call a function through a member variable?
- Returning a closure from a function
- How to return an anonymous type from a trait method without using Box?
- Closures as a type in a Rust struct
- Types of unboxed closures being unique to each
- Why does passing a closure to function which accepts a function pointer not work?
- What does "dyn" mean in a type?
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).