HiveBrain v1.2.0
Get Started
← Back to all entries
snippetrustMajor

How do I store a closure in a struct in Rust?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
howstructstorerustclosure

Problem

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 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 {
    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

Solution

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 usize>. This is the most efficient, but it does mean that a specific Foo 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 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 procs were heap-allocated and were equivalent to Box usize> (you can only call a proc once).

Code Snippets

let foo = Foo { foo: |x| x + 1 };
let foo: Foo<_> = Foo { foo: |x| x + 1 };

Context

Stack Overflow Q#27831944, score: 67

Revisions (0)

No revisions yet.