Let's go step by step over your request.
Trait bound
For starters, let's look at the function signature you requested:
-
&Vec<T>
offers no useful API w.r.t, the slice it can refer to, &[T]
; so let's use that and be more general (for instance, we may avoid the heap-allocation that creating a non-empty Vec
requires).
-
&'_ ... &'static T
is, similarly, not better than the more general &'_ ... &'_ T
, unless you intend to store those &'static T
somewhere during the call (unlikely). So let's use the latter.
-
static ... FnMut
is an oxymoron: static
implies sharing (&
access), FnMut
requires lack thereof (&mut
exclusive access).
-
static ... + 'static
A static, even a "thread-local one", may live arbitrarily long, thus the values it holds must be safe to hold that long. Such property is expressed as that of having a 'static
bound.
For instance:
-
&'static _ : 'static
An infinitely-long borrow of a value can be held infinitely long.
-
String : 'static
Although not all String
live infinitely long (quite the opposite, actually), one that you hold will live until you drop it. Thus, a String
can be held infinitely long.
-
ditto for all non-generic types.
Counter examples:
-
&'a _
for some lifetime 'a
which is unknown, universal, or referring to a local variable, cannot be held infinitely long.
Indeed, past the end of the lifetime, the variable the reference refers to may no longer exist, thus leading to a dangling pointer.
So, in our case, we need that the closure (environment / captures) be 'static
.
This leads us to the now fixed closure signature / API / interface / trait bound:
Fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
+ 'static
Making a type out of a trait bound
We have, up until now, decided what the trait bound / the contract of the held type should be.
Now remains the question of what should be the type of some implementor of the contract we wish to hold.
We have, for instance, a very simple implementor of closure API: good ol' function( pointer)s, with their lack of captured environment:
// the type of function pointers / capture-less closures...
fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
// implements...
:
// our required API:
Fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
+ 'static
And now we have our first working solution!
thread_local! {
static STRATEGY
: fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
= |objs| {
println!("{}", objs.len());
None
}
;
}
fn main ()
{
STRATEGY.with(|strategy| {
strategy(&[]);
strategy(&[&OtherObject,]);
});
}
From this point, there are three possibilities:
-
You are satisfied with the situation, since you do not need the closures to capture/use an environment 
-
You need to capture an environment, but realise that a global function can use its own private globals as an environment: Example 
-
Since using global variables isn't great, you are thinking about refactoring the code into not using globals anymore, so you need a more general solution, while still having the aforementioned trait bounds constraints
keep reading
Other implementors of the trait bound
So, we have seen that function pointers are a concrete / nameable type, easy to construct, and which implements the given trait bounds; all thanks to its not requiring any environment.
But what happens when we need some environment / state for our closure?
In that case, we have two possibilities:
-
"static" (compile-time) / exact / fixed knowledge of the type (and thus size and layout) of our implementor.
-
dynamic closure type (i.e., the exact type (and thus size and layout) of the closure is "not known" at compile-time, so as to be able to, for instance, swap an instance of one type with another of another type, etc.)
dyn
-amic closure type
This the (in)famous dyn <(object-safe) trait bounds>
type.
So, in our case, the type is:
dyn 'static + Fn(&'_ [&'_ OtherObject]) -> Option<...>
such a type, as mentioned above, may have instances of different sizes and layouts (we say the type is not Sized
). Thus, using them requires (pointer) indirection:
-
&'_ mut (dyn ...)
Indirection by exclusive reference / borrow,
- Too restrictive in our case, since the
Fn
trait only requires shared &self
access 
-
&'_ (dyn ...)
Indirection by shared reference / borrow,
- Given our
'static
requirement, this implies the concrete &'static (dyn ...)
, which, realistically, isn't gonna be happening often (except for the fn
pointer-like closures, for which there is the simpler solution of using the fn
pointer directly). 
-
Box<dyn ...>, Rc<dyn ...>, Arc<dyn ...>
Indirection by an owning pointer (Box
for an exclusive such pointer, Rc
for a shared thread-local one, and Arc
otherwise).
- In our case, all three pointers could be used; but given that we do not need the reference counting, we are gonna go and use a
Box

thread_local! {
static STRATEGY
: Box<dyn 'static +
Fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
>
= Box::new({
use ::core::cell::Cell;
let counter = Cell::new(0);
move |objs| {
let counter = counter.replace(counter.get() + 1);
dbg!((counter, objs.len()));
None
}
})
;
}
Inlineable closure type
As you may have noticed, the Box<dyn ...>
requires an allocation, much like c++'s std::function
(implicitly) does.
To avoid the heap-allocation, one needs a compile-time fixed type, to be able to inline the closure within the (global) memory of the program, whose layout must be known at compile-time (≠ heap memory).
The classic way to do this in Rust is to define your own struct
, and ensure it meets the trait bounds by impl
ementing the required traits.
The problem in this case, is that one cannot implement the Fn
trait(s) in stable Rust!
To work around this, one must use a classic traits rather than the special Fn
ones, thus having to drop the ()
call sugar when using an implementor of the trait:
trait MyFn : 'static {
fn call (self: &'_ Self, objs: &'_ [&'_ OtherObject])
-> Option<JoinHandle<()>>
;
}
/// Optional: Make closures implement `MyFn`
impl<F> MyFn for F
where
F : 'static + Fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
{
fn call (self: &'_ Self, objs: &'_ [&'_ OtherObject])
-> Option<JoinHandle<()>>
{
self(objs)
}
}
use ::core::cell::Cell;
struct MyImplFnState {
counter: Cell<usize>,
}
thread_local! {
static STRATEGY: MyImplFnState = {
let counter = Cell::new(0);
return MyImplFnState {
counter,
};
// where
impl MyFn for MyImplFnState {
fn call (self: &'_ MyImplFnState, objs: &'_ [&'_ OtherObject])
-> Option<JoinHandle<()>>
{
let Self { counter } = self;
let counter = counter.replace(counter.get() + 1);
dbg!((counter, objs.len()));
None
}
}
};
}
fn main ()
{
STRATEGY.with(|strategy| {
strategy.call(&[]);
strategy.call(&[]);
strategy.call(&[]);
strategy.call(&[&OtherObject,]);
});
}
The classic way to do this in Rust is to define your own struct
, and ensure it meets the trait bounds by impl
ementing the required traits.
But, in nightly
, there is another way: that of using impl ...
type-erasure anywhere. Which you seem to have attempted to use. To be able to use impl ...
anywhere, one must use:
-
A type SomeHiddenImplementor = impl ...
type alias;
-
Have a function definition that returns SomeHiddenImplementor
, to tie the hidden type to the actual type used in the implementation of that function.
#![feature(type_alias_impl_trait)]
type MyImplFn =
impl 'static + Fn(&'_ [&'_ OtherObject]) -> Option<JoinHandle<()>>
;
thread_local! {
static STRATEGY
: MyImplFn
= {
return new_MyImplFn();
// where
#[allow(nonstandard_style)]
fn new_MyImplFn () -> MyImplFn
{
use ::core::cell::Cell;
let counter = Cell::new(0);
move |objs| {
let counter = counter.replace(counter.get() + 1);
dbg!((counter, objs.len()));
None
}
}
}
;
}